views:

887

answers:

4

I'm using MSTEST inside Visual Studio 2008. How can I have each unit test method in a certain test class act as if it were the first test to run so that all global state is reset before running each test? I do not want to explicitly clean up the world using TestInitialize, ClassInitialize, AssemblyInitialize, etc. For example:

[TestClass]
public class MyClassTests
{
    [TestMethod]
    public void Test1()
    {
       // The "Instance" property creates a new instance of "SomeSingleton"
       // if it hasn't been created before.
       var i1 = SomeSingleton.Instance;
       ...
    }
    [TestMethod]
    public void Test2()
    {
       // When I select "Test1" and "Test2" to run, I'd like Test2
       // to have a new AppDomain feel so that the static variable inside
       // of "SomeSingleton" is reset (it was previously set in Test1) on
       // the call to ".Instance"
       var i2 = SomeSingleton.Instance;
       // some code
    }

Although a similar question appeared on this topic, it only clarified that tests do not run in parallel. I realize that tests run serially, but there doesn't seem to be a way to explicitly force a new AppDomain for each method (or something equivalent to clear all state).

Ideally, I'd like to specify this behavior for only a small subset of my unit tests so that I don't have to pay the penalty of a new AppDomain creation for tests that don't care about global state (the vast majority of my tests).

A: 

We had a similar issue arise with our MSTests. We handled it by calling a function at the beginning and end of the specific tests that needed it.

We are storing a test expiration date in our app configuration. Three tests needed this date to fall into a specific range to determine the appropriate values. The way our application is set up, the configuration values would only be reset if there was not a value assigned in session. So, we created two new private static functions - one to explicitly set the configuration value to a specified date and one to clear that date from session after the test runs. In our three tests, we called these two functions. When the next test runs, the application sees an empty value for the date and refetches it from the configuration file.

I'm not sure if that's helpful, but that was how we worked around our similar issue.

Seems like you might be able to use [TestInitialize] in your test class?
Jeff Moser
A: 

I think you are looking for the TestIntialize attribute and the TestCleanUp attribute. Here is an MSDN blog showing the execution orderlink text

Alex
Thanks for the answer. I was looking for something that would clean up the world without having to explicitly clear out each variable, but I'm not sure if that's possible.
Jeff Moser
+1  A: 

In the end, I wrote a helper that used AppDomain.CreateDomain and then used reflection to call the unit test under a different AppDomain. It provides the isolation I needed.

This post on MSDN's forums shows how to handle the situation if you only have a few statics that need to be reset. It does mention some options (e.g. using Reflection and PrivateType ).

I continue to welcome any further ideas, especially if I'm missing something obvious about MSTEST.

Thanks!

Jeff Moser
+1  A: 

Add a helper in your tests that uses reflection to delete the singleton instance (you can add a reset method to the singleton as well, but I would be concerned about its use). Something like:

public static class SingletonHelper {
            public static void CleanDALFactory() 
            {
                    typeof(DalFactory)
                        .GetField("_instance",BindingFlags.Static | BindingFlags.NonPublic)
                        .SetValue(null, null);
            }
}

Call this in your TestInitialize method. [ I know this is "cleaning up the world", but you only have to write the method once in a helper per singleton, its very trivial and gives you explicit control ]

Watson
Thanks for the answer. I think that I'll have to use a combination of Reflection to iterate over the static fields and roughly what you describe here. Something like a "NullifyStaticFields(Type t)" to make it reusable
Jeff Moser