locked
TestContext.DataRow null in Data Driven Test RRS feed

  • Question

  • So I have a testing solution with multiple Data driven test classes in VS2010. One of the test classes looks as follows;

    [TestClass]
        public class UserTableEntryTests
        {
            public static TestContext TestContext;
            internal static RuleHelpers _ruleHelper;
            internal static UserTableEntry _user;
    
            [AssemblyInitialize()]
            public static void Initialize(TestContext context)
            {
                TestContext = context;
                _ruleHelper = new RuleHelpers();
            }
    
            [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\UserTableEntryData.csv", "UserTableEntryData#csv", DataAccessMethod.Sequential), DeploymentItem("UserTableEntryData.csv"), TestMethod]
            public void LoadUserTableEntryTestData()
            {
                _user = new UserTableEntry();
                _user.LogicalDate = Convert.ToDateTime(TestContext.DataRow["LogicalDate"]);
                _user.ApplicationBatchType = Convert.ToInt32(TestContext.DataRow["ApplicationBatchType"]);
                _user.ApplicationBatchTypeName = Convert.ToString(TestContext.DataRow["ApplicationBatchTypeName"]);
                        .
                        .
                        .
                 remaining ommited   

    This works great, the LoadUserTableEntryTestData method has a valid TestContext with a non-null DataRow property and the test data is loaded from the csv file. The only problem here is that the Initialize method is marked as AssemblyInitialize so its the only class that works. When I change the attribute to ClassInitialize everything stops working as it should. The Initialize method is still called with a valid TestContext, however LoadUserTableEntryTestData has a null DataRow property on the context and so the whole thing fails with NullReferenceException. None of the test code or csv data has changed, so why does AssemblyInitialize cause the data to load correctly but  ClassInitialize does not? I have over 100 test classes in the solution but only 1 of them will run successfully at any particular time. Its a problem.

    Any ideas?

    Thanks 


    • Edited by phlaz Wednesday, November 14, 2012 9:23 AM
    Wednesday, November 14, 2012 9:04 AM

Answers

  • So I tried removing the Initialize method completely and added a public TestContext property;

    private TestContext _testContext;
    public TestContext TestContext
    {
        get { return _testContext; }
        set { _testContext = value; }
    }

    This is being populated correctly and I now have access to the DataRow property, which is non-null. Strange that when I use the TestContext I get from the method marked with the Initialize attribute that it doesnt work. Hopefully this will be of use to others who experience the same problem.

     
    • Marked as answer by phlaz Thursday, November 15, 2012 8:48 AM
    Thursday, November 15, 2012 8:48 AM

All replies

  • Hello Phlaz,

    Thank you for posting in the MSDN forum.

    AssemblyInitialize attribute identifies a method to be used before all tests in the assembly have run and to allocate resources obtained by the assembly.

    ClassInitialize attribute identifies a method to be used before any of the tests in the test class have run and to allocate resources to be used by the test class.

    For detailed information, please see the following articles:

    AssemblyInitializeAttribute Class

    ClassInitializeAttribute Class
    I would like to know if you have only one Initialize(TestContext context) method in your test solution. If so, as my understanding, when you use AssemblyInitialize attribute, the Initialize method will always run once when you run any of the tests. So the TestContext can be initialized.

    But when you use ClassInitialize attribute, the Initialize method will run only in the specified test class. When you run other tests in another test class, the TestContext can’t be initialized.

    Best regards,


    Amanda Zhu [MSFT]
    MSDN Community Support | Feedback to us

    Thursday, November 15, 2012 1:24 AM
  • Hi Amanda

    Yes, every test class in the project has a Initialize method, this is required to get access to the TestContext object. I dont think the Initialize method is the problem, it always runs regardless of whether its marked with the AssemblyInitialize attribute or the ClassInitialize attribute, and I always have a valid TestContext object. The problem is in the LoadUserEntryTestData where I need access to the data in the csv file which is normally accessbile via the DataRow property of the TestContext object. When the Initialize method is marked with the CLassInitialize attribute, DataRow is null in LoadUserEntryTestData, but when its marked with AssemblyInitialize DataRow contains the current row from the datasource as expected.

    Every class has the Initialze method and an equivalent LoadUserEntryTestData, just with a different name, like LoadFirmTestData, and a different data source, which loads the data specific to the tests being run by that class. It seems like only a single data source can be bound to the assembly in any particular test run, because AssemblyInitialize is the only way it works successfully. Is this the expected behaviour? Surely the same functionality should still work when using ClassInitialize?

    This problem is completely reproducable. If you create a standard test project with a single test class mapped to a csv data source via the DataSource attribute, the data is retrieved successfully by the TestContext object from the data source when the method that retrieves the TestContext object is marked with AssemblyInitialize, when its marked with ClassInitialize it fails, but only because the DataRow property is always null.

    [TestClass]
        public class UnitTest1
        {
            static TestContext _context;
    
            [AssemblyInitialize]
            public static void Initilize(TestContext context)
            {
                _context = context;
            }
    
            [DataSource("Microsoft.VisualStudio.TestTools.DataSource.CSV", "|DataDirectory|\\CalendarData.csv", "CalendarData#csv", DataAccessMethod.Sequential), DeploymentItem("CalendarData.csv"), TestMethod]
            public void LoadDataTest()
            {
                if (_context.DataRow == null) Assert.Fail("DataRow is null, test cannot run");
            }
        }
    Can you also confirm that the only way I can get access to the TestContext object is by storing a static instance of it obtained from a method marked with either the AssemblyInitialize or ClassInitialize attribute, as in the above sample test? I ask because all of the Microsoft examples of getting the TestContext only show the property definition of the TestContext but dont actually assign it to the property from the initilize method, so if you copy and paste these examples as is, none of them actually work because by the time you get to the test you dont have an instance of the TestContext.





    • Edited by phlaz Thursday, November 15, 2012 8:28 AM
    Thursday, November 15, 2012 7:53 AM
  • So I tried removing the Initialize method completely and added a public TestContext property;

    private TestContext _testContext;
    public TestContext TestContext
    {
        get { return _testContext; }
        set { _testContext = value; }
    }

    This is being populated correctly and I now have access to the DataRow property, which is non-null. Strange that when I use the TestContext I get from the method marked with the Initialize attribute that it doesnt work. Hopefully this will be of use to others who experience the same problem.

     
    • Marked as answer by phlaz Thursday, November 15, 2012 8:48 AM
    Thursday, November 15, 2012 8:48 AM