7

Pensé que el propósito de estos atributos era ejecutarlos solo una vez por ensamblado. Tengo una clase simple de la siguiente manera:¿Por qué se invocan [AssemblyInitialize] y [AssemblyCleanup] dos veces en el mismo ensamblaje de proyecto de prueba?

[TestClass] 
public class AssemblyIntegrationTestSetup 
{ 
    public AssemblyIntegrationTestSetup() { } 
    public TestContext TestContext { get; set; } 

    [AssemblyInitialize] 
    public static void SetupIntegrationTests(TestContext context) 
    { 
     WindowsServiceService.Instance.StartService("Distributed Transaction Coordinator"); 
    } 

    [AssemblyCleanup] 
    public static void TeardownIntegrationTests() 
    { 
      WindowsServiceService.Instance.StopService("Distributed Transaction Coordinator"); 
    } 

} 

Sin embargo, cuando ejecuto el banco de pruebas del nivel de ensamblado inicializar y ejecutar Métodos de limpieza dos veces. Aquí están los detalles sobre mi entorno:

  1. Todas las clases de prueba están en el mismo proyecto/ensamblado.
  2. Tengo pruebas de integración y unidad separadas por espacio de nombres.
  3. Para las pruebas de integración, estoy usando MSTextExtensions para permitir la reversión en las transacciones de la base de datos.
  4. También estoy comenzando/deteniendo el servicio DTC de MS SQL Server, que se requiere para la capacidad de reversión. Quería hacer esto una vez por suite de prueba (y el mejor compromiso que encontré fue usar los atributos de nivel de ensamblaje). El código funcionará, pero se ejecuta dos veces.
  5. Si es importante, también estoy usando Microsoft Moles Framework en algunas de mis pruebas.

El comportamiento observado es similar a:

AssemblyInitialize   

Class1.TestInitialize 
Class1.TestMethod1 
Class1.TestCleanup 

AssemblyInitalize   <-- //This shouldn't be happening right? 

Class2.TestInitialize 
Class2.TestMethod1 
Class2.TestCleanup 

Class2.TestInitialize 
Class2.TestMethod2 
Class2.TestCleanup 

Class5.TestInitialize 
Class5.TestMethod1 
Class5.TestCleanup 

Class7.TestInitialize 
Class7.TestMethod1 
Class7.TestCleanup 

//More random bouncing around then... 

AssemblyCleanup 
AssemblyCleanup   <-- //This shouldn't be happening right? 

Respuesta

5

Desde el artículo de MSDN:

Importante

Este atributo no debe usarse en ASP.NET pruebas unitarias, es decir, cualquier prueba con [HostType ("ASP.NET")] atribuir te Debido a la naturaleza sin estado de IIS y ASP.NET, un método decorado con este atributo se podría llamar más que una vez por ejecución de prueba.


Hay unos pocos mandos que se pueden manipular en el corredor de prueba. Me acaba de despejar el problema con un contador:

private int InitCount; 

[AssemblyInitialize] 
public static void SetupIntegrationTests(TestContext context) 
{ 
    if (InitCount++ == 0) { 
     WindowsServiceService.Instance.StartService("Distributed Transaction Coordinator"); 
    } 
} 

[AssemblyCleanup] 
public static void TeardownIntegrationTests() 
{ 
     if (--InitCount == 0) { 
      WindowsServiceService.Instance.StopService("Distributed Transaction Coordinator"); 
     } 
} 
+0

Lo vi en la documentación, pero no sabía si esa era la causa segura. Tengo una publicación separada en los foros de Pex y Moles de MSDN sobre el atributo de tipo de host: http://social.msdn.microsoft.com/Forums/en-US/pex/thread/b690442b-0333-42b8-928c-6f5f8bc44b02. No estoy seguro de que ese sea el problema, ya que esa nota es sobre ASP.NET e IIS. Además, por lo que puedo decir, MS Moles simplemente no le permitirá agregar el atributo HostType a los métodos AssemblyInitialize/Cleanup. Pero, ¿y los otros? Eso es lo que estoy preguntando allí. – Matt

+0

@Matt - publicación actualizada. –

1

Pues bien, esta respuesta es un bazillion años de retraso según la fecha problema original, pero ...

he descubierto si el agente de prueba (QTAgent32.exe) se cuelga o muere antes de que la secuencia completa finalice, entonces AssemblyInitialize (y tal vez ClassInitialize y TestInitialize) se volvería a llamar. Por ejemplo, ponga esto en su función [AssemblyCleanup] y verá produciría el comportamiento:

Process p = AutotestShared.RunProcess("cmd", "/c taskkill /t /f /im QTAgent32.exe", true); 
p.WaitForExit(); 

Así que la moraleja de esta historia es: Comprobar sus funciones de limpieza para ver si hay alguna choques/corrupción. Las fallas durante la limpieza no se muestran en el informe de prueba porque las afirmaciones de aprobado/no aprobado ya están completas. Pero los problemas que causa pueden aparecer de otras maneras.

Cuestiones relacionadas