Why is [AssemblyInitialize] and [AssemblyCleanup] being called twice in same test project assembly?

integration-testing, mstest, unit-testing, visual-studio-2008

Solution

From the MSDN Library article:

Important

This attribute should not be used on ASP.NET unit tests, that is, any test with [HostType("ASP.NET")] attribute. Because of the stateless nature of IIS and ASP.NET, a method decorated with this attribute might be called more than once per test run.

There are few knobs you can tweak in test runner. I would just punt the problem with a counter:

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");
      }
}

Problem

I thought the whole purpose of these attributes was to run them only once per assembly. I have a simple class as follows: ``` [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"); } } ``` However when I run the test suite the assembly-level Initialize and Cleanup methods execute twice. Here are the details about my environemnt: - All test classes are in the same project/assembly. - I have integration and unit tests separated by namespace. - For the integration tests, I am using MSTextExtensions to allow for rollback on database transactions. - I am also starting/stopping the MS SQL Server DTC service, which is required for the rollback ability. I wanted to do this once per test suite run (and the best compromise I found was to use the Assembly-level attributes). The code will work, but it executes twice. - If it matters, I'm using also the Microsoft Moles Framework in some of my tests. The observed behavior is similar to: ``` 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? ```

Original source