2011-10-01 14 views
5

He aislado las pruebas NUnit para mi aplicación C# en un ensamblado llamado Tests.dll. El archivo de configuración asociado se llama Tests.dll.config. Esto es lo que utiliza Nunit en lugar del archivo de configuración real de mi aplicación. Parece que este (sólo mostrando un par de opciones de configuración que hay muchos más):Manipulación del archivo app.config para pruebas unitarias

<?xml version="1.0" encoding="utf-8"?> 

<configuration> 
    <appSettings> 
    <add key="useHostsFile" value="true" /> 
    <add key="importFile" value="true" /> 

    </appSettings> 
</configuration> 

para asegurar mi aplicación ha sido probada, necesitaré para cambiar las opciones de configuración entre las pruebas. Después de ejecutar algunas pruebas, me gustaría agregar algunos valores de configuración nuevos al archivo y utilizarlos en pruebas posteriores. ¿Qué código necesitaría agregar para hacer esto?

+0

¿Puede explicar mejor el caso de uso? ¿Por qué necesitarías cambiar el test.dll.config en tiempo de ejecución? –

+1

Esta es exactamente la misma pregunta que esta: http://stackoverflow.com/questions/168931/unit-testing-the-app-config-file-with-nunit –

+0

Bien, supongo que se puede cerrar. Gracias por el puntero. – FunLovinCoder

Respuesta

3

Recomiendo implementar una interfaz IConfig con propiedades useHostsFile e importFile. Luego eliminaría todas las dependencias directas de este archivo, excepto en Class ConfigDefault, que implementa IConfig. En esta implementación, carga su archivo de configuración normal. Para cada prueba puede implementar otra clase que también hereda de IConfig. Sugiero usar una Inyección de Dependencia. Ninject es gratis y fácil de usar.

0

utilizo este código:

[TestMethod] 
    public void Test_general() 
    { 
     var cs = new ConnectionStringSettings(); 
     cs.Name = "ConnectionStrings.Oracle"; 
     cs.ConnectionString = "DATA SOURCE=xxx;PASSWORD=xxx;PERSIST SECURITY INFO=True;USER ID=xxx"; 
     cs.ProviderName = "Oracle.DataAccess.Client"; 

     var config = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None); 
     //config.ConnectionStrings.ConnectionStrings.Clear(); 
     config.ConnectionStrings.ConnectionStrings.Remove(cs.Name); 
     config.ConnectionStrings.ConnectionStrings.Add(cs); 
     config.Save(ConfigurationSaveMode.Modified); 
     ConfigurationManager.RefreshSection("connectionStrings"); 

     // your code for your test here 
    } 
0

Aquí está mi granito de arena a este desafío. Simplemente, cree una nueva clase AppSettings como una capa de abstracción. En operaciones normales, simplemente leerá la configuración desde el archivo de configuración de la aplicación. Pero las pruebas unitarias pueden anular la configuración en cada subproceso, lo que permite que las pruebas unitarias se ejecuten en paralelo con diferentes configuraciones.

internal sealed class AppSettings 
{ 
    private static readonly AppSettings instance; 
    private static ConcurrentDictionary<int, AppSettings> threadInstances; 
    private string _setting1; 
    private string _setting2; 

    static AppSettings() { instance = new AppSettings(); } 

    internal AppSettings(string setting1 = null, string setting2 = null) { 
     _setting1 = setting1 != null ? setting1 : Properties.Settings.Default.Setting1; 
     _setting2 = setting2 != null ? setting2 : Properties.Settings.Default.Setting2; 
    } 

    internal static AppSettings Instance { 
     get { 
      if (threadInstances != null) { 
       AppSettings threadInstance; 
       if (threadedInstances.TryGetValue(Thread.CurrentThread.ManagedThreadId, out threadInstance)) { 
        return threadInstance; 
       } 
      } 
      return instance; 
     } 

     set { 
      if (threadInstances == null) { 
       lock (instance) { 
        if (threadInstances == null) { 
         int numProcs = Environment.ProcessorCount; 
         int concurrencyLevel = numProcs * 2; 
         threadInstances = new ConcurrentDictionary<int, AppSettings>(concurrencyLevel, 5); 
        } 
       } 
      } 

      if (value != null) { 
       threadInstances.AddOrUpdate(Thread.CurrentThread.ManagedThreadId, value, (key, oldValue) => value); 
      } else { 
       AppSettings threadInstance; 
       threadInstances.TryRemove(Thread.CurrentThread.ManagedThreadId, out threadInstance); 
      } 
     } 
    } 

    internal static string Setting1 => Instance._setting1; 

    internal static string Setting2 => Instance._setting2; 
} 

En el código de aplicación, la configuración de acceso utilizando las propiedades estáticas:

function void MyApplicationMethod() { 
    string setting1 = AppSettings.Setting1; 
    string setting2 = AppSettings.Setting2; 
} 

En pruebas de unidad, la configuración opcionalmente anular seleccionados:

[TestClass] 
public class MyUnitTest 
{ 
    [TestCleanup] 
    public void CleanupTest() 
    { 
     // 
     // Clear any app settings that were applied for the current test runner thread. 
     // 
     AppSettings.Instance = null; 
    } 

    [TestMethod] 
    public void MyUnitMethod() 
    { 
     AppSettings.Instance = new AppSettings(setting1: "New settings value for current thread"); 
     // Your test code goes here 
    } 
} 

Nota: Como todos los métodos de los AppSettings la clase se declara como interna, es necesario hacerla visible para el conjunto de prueba de la unidad utilizando el atributo: [assembly: InternalsVisibleTo ("< nombre de conjunto >, PublicKey = < clave pública > ")]