Dennis Stone's Blog

  • Using a Base Class for your Unit Test Classes

    Overview:

    This post will go over some simple but effective ways to setup common initialization and cleanup for Unit Tests on a larger scale than [ClassInitialize] and [TestInitialize] methods can provide for.

    First, to establish a common starting point I’ll go over some of the basics, if you’re already familiar with using the ClassInitialize/Cleanup and TestInitialize/Cleanup attributes in unit tests you may wish to skip this next part.

     

    Background:

    When you have some setup and cleanup code that needs to run for several unit tests typically you would put them in the same Test Class and use a combination of Class Initialize/Cleanup and Test Initialize/Cleanup methods. 

    A simple start would be something like this: 

        [TestClass]

        public class TestClass1

        {

            [TestInitialize]

            public void TestInit()

            {

                Console.WriteLine("TestClass1.TestInit()");

            }

     

            [TestMethod]

            public void TestMethod1()

            {

                Console.WriteLine("TestClass1.TestMethod1()");

            }

     

            [TestMethod]

            public void TestMethod2()

            {

                Console.WriteLine("TestClass1.TestMethod2()");

            }

     

            [TestCleanup]

            public void TestCleanup()

            {

                Console.WriteLine("TestClass1.TestCleanup()");

            }

        }

    If you run both tests here the output will be:

    TestClass1.TestInit()

    TestClass1.TestMethod1()

    TestClass1.TestCleanup()

    and

    TestClass1.TestInit()

    TestClass1.TestMethod2()

    TestClass1.TestCleanup()

    The methods marked with the attributes [TestInitialize] and [TestCleanup] run before and after each test in that class.  If instead you’d like to only run the initialization code once before all tests (not each individual test) you could use [ClassInitialize] and [ClassCleanup] instead, or you can also use them in combination.

     

    Going Beyond Local ClassInitialize and TestInitialize

    What can I do if I have a large project, with dozens or even hundreds of unit test methods spread across several classes and you want to share some setup or cleanup code between those tests? 

    One approach would be to create some initialize and cleanup helper methods in a separate class and call those methods from each of your individual test classes initialize and cleanup methods. 

    Another approach, the one I personally prefer, is to create a base class for your test classes.  For example: 

        [TestClass]

        public class TestBase

        {

            [TestInitialize]

            public void BaseTestInit()

            {

                Log.AppendLine("TestBase.BaseTestInit()");

            }

     

            [TestCleanup]

            public void BaseTestCleanup()

            {

                Console.WriteLine(Log.ToString());

            }

     

            public static StringBuilder Log

            {

                get

                {

                    if (s_log == null)

                    {

                        s_log = new StringBuilder();

                    }

     

                    return s_log;

                }

            }

     

            static StringBuilder s_log;

        }

           

        [TestClass]

        public class TestClass1 : TestBase

        {

            [ClassInitialize]

            public static void ClassInit(TestContext testContext)

            {

                Log.AppendLine("TestClass1.ClassInit()");

            }

     

            [TestInitialize]

            public void TestInit()

            {

                Log.AppendLine("TestClass1.TestInit()");

            }

     

            [TestMethod]

            public void TestMethod1()

            {

                Log.AppendLine("TestClass1.TestMethod1()");

            }

        } 

    Notice that the base class “TestBase” is also using the [TestClass] attribute, although we won’t be putting any test methods in this class.  This allows the use of the [TestInitialize] and [TestCleanup] attributes within our base class.  If you ran the tests in TestClass1 you would see the following output: 

    TestClass1.ClassInit()

    TestBase.BaseTestInit()

    TestClass1.TestInit()

    TestClass1.TestMethod1() 

    The [ClassInitialize] will always run first, it’s static and will be invoked by the unit test engine before instantiating the test class.  Next we see that the Test Initializer in the base class is called, followed by the Test Initializer in the test class itself, and lastly the test method is executed. 

     

    How can I create an initialization method that will run before any class initialization methods in my test project? 

    Building on the common base class approach described above you could simply add a static constructor to your base class and either perform the initialization there or call the method that will perform the desired initialization.  The resulting base class might look like this: 

        [TestClass]

        public class TestBase

        {

            static TestBase()

            {

                s_log = new StringBuilder();

                Log.AppendLine("TestBase.ctor()");

            }

     

            [TestInitialize]

            public void BaseTestInit()

            {

                Log.AppendLine("TestBase.BaseTestInit()");

            }

     

            [TestCleanup]

            public void BaseTestCleanup()

            {

                Console.WriteLine(Log.ToString());

            }

     

            public static StringBuilder Log

            {

                get { return s_log; }

            }

     

            static StringBuilder s_log;

        } 

     

    Will the same approach that was used for [TestInitialize] work with [ClassInitialize] in a base class? 

    Not exactly, if you create a [ClassInitialize] attributed method in the base class it won’t ever get called unless you explicitly call it at the beginning of your derived test classes ClassInitialize method; which of course is nowhere near as nice as the above approach. 

    If you really wanted this functionality you could hook the method calls using reflection and set things up that way, but that’s beyond the scope of this post. 

    Setting up the relationship in the reverse would be much easier, but is of questionable value.   By reverse order I mean that it would be easier to create a method that resided in the base class and was called once per test class but it would be called after the derived classes ClassInitialize method. 

    The only viable option that I can come up for achieving an inheritable class initialization approach would be to ditch the ClassInitialize mechanism altogether and go back to good old fashioned  class constructors. 

    Example: 

        [TestClass]

        public class TestBase

        {

            static TestBase()

            {

                s_log = new StringBuilder();

                Log.AppendLine("TestBase.ctor()");

            }

     

            public TestBase()

            {

                Log.AppendLine("TestBase.TestBase() <-- acts as ClassInitialize in base");

            }

                   

            [TestInitialize]

            public void BaseTestInit()

            {

                Log.AppendLine("TestBase.BaseTestInit()");

            }

     

            [TestCleanup]

            public void BaseTestCleanup()

            {

                Console.WriteLine(Log.ToString());

            }

     

            public static StringBuilder Log

            {

                get { return s_log; }

            }

     

            static StringBuilder s_log;

        }

     

        [TestClass]

        public class TestClass1 : TestBase

        {

            public TestClass1() //Replaces ClassInitialize method

            {

                Log.AppendLine("TestClass1.TestClass1() <-- acts as ClassInitialize in derived");

            }

     

            [TestInitialize]

            public void TestInit()

            {

                Log.AppendLine("TestClass1.TestInit()");

            }

     

            [TestMethod]

            public void TestMethod1()

            {

                Log.AppendLine("TestClass1.TestMethod1()");

            }

        } 

    Running TestMethod1 in the derived class produces the following output: 

    TestBase.ctor()

    TestBase.TestBase() <-- acts as ClassInitialize in base

    TestClass1.TestClass1() <-- acts as ClassInitialize in derived

    TestBase.BaseTestInit()

    TestClass1.TestInit()

    TestClass1.TestMethod1()

     

  • Orcas WebTest API Enhancements

    Several new API Enhancements have been made for WebTest's in the Orcas release of Visual Studio Team System.  Here are some links to examples:

    DeclarativeWebTest & DeclarativeWebTestSerializer:  http://blogs.msdn.com/densto/pages/declarativewebtest-declarativewebtestserializer.aspx

    WebTestRequest.DependentRequests Collection: http://blogs.msdn.com/densto/pages/webtestrequest-dependentrequests-collection.aspx

    WebTest.Outcome & WebTestRequest.Outcome: http://blogs.msdn.com/densto/pages/webtest-outcome-webtestrequest-outcome.aspx

    To find out about more of the new additions to Orcas check out the links in this post: http://forums.microsoft.com/MSDN/ShowPost.aspx?PostID=1177487&SiteID=1

  • How to Databind Web Test Properties that don't have the Databinding Dropdown UI in the Property Grid

    Most of the time when you want to bind a web test, request, validation rule, or extraction rule property to a datasource you just click on the value in the properties grid and there is a dropdown that provides UI for selecting the datasource to bind to.  Sometimes you'll find properties that don't provide this UI but you'll want to databind the value anyways.  In most cases this it's possible, here are an easy set of steps to do this:

    1. Add the datasource that contains the dynamic values you want to bind to the property.
    2. Add a Querystring parameter to one of the requests in your Web Test, it doesn’t matter which one, we’re going to delete this when we’re done.
    3. Bind the Querystring parameter to the datasource in the way you’d like to bind the property value that doesn’t have this binding UI.
    4. Look at how the querystring value looks in the editor after binding, it’ll be something like:  {{datasourceName.tableName.fieldName}}
    5. Type that exact text, including the surrounding {{ }} into the value’s text field where you want the real binding.
    6. Now you can delete the querystring parameter you added.

    That’s it, you should be able to databind just about any property in the grid that doesn’t have the databinding UI by default using this method.

     

  • Dynamic QueryString Correlation: Custom Extraction Rules and WebTest Plug-in

    Here is an article with some custom rules and plug-ins that you can use to apply dynamic querystring correlation to your web tests.  These can be useful if you are testing a site that uses querystring parameters to track dynamic values (such as session id), for example, a SQL Reporting Services site.

    http://blogs.msdn.com/densto/pages/dynamic-querystring-correlation-custom-extraction-rules-and-webtest-plug-in.aspx


© 2008 Microsoft Corporation. All rights reserved. Terms of Use  |  Trademarks  |  Privacy Statement
Microsoft
Page view tracker