Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Data driven tests generated in ClassInitialize: no longer working in Visual Studio 2012

I have upgraded from Visual Studio 2010 to Visual Studio 2012.

In my unit test project, I have a [ClassInitialize] method which generates a CSV file which I then feed into a data-driven [TestMethod] using [DataSource] connected to the CSV.

This works great in Visual Studio 2010.

I cannot get this to work in Visual Studio 2012.

It seems that in VS2012 the MS test runner requires the file connected to the [DataSource] to already exist otherwise none of the tests will run. If I create the CSV myself, the data-driven tests run, but they do not pick up the data created in [ClassInitialize]: it seems that the list of tests from the [DataSource] is evaluated BEFORE [ClassInitialize] runs.

Is there a workaround?


This is a minimal project that reproduces the problem. For me, this succeeds in VS2010 but fails in VS2012.

TestProject.cs

using System.Diagnostics;
using System.IO;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace TestProject
{
    [TestClass]
    public class DataDrivenUnitTest
    {
        private static bool _classInitializeCalled;
        private static int _testCount;

        public TestContext TestContext { get; set; }

        [ClassInitialize]
        public static void ClassInitialize(TestContext testContext)
        {
            // Generate the csv list of tests
            //TestContext = testContext;
            _classInitializeCalled = true;
            string testDirectory;
            testDirectory = testContext.DeploymentDirectory;
            using (var f = new StreamWriter(testDirectory + @"\" + "TestList.csv"))
            {
                f.WriteLine("TestName");
                f.WriteLine("TestA");
                f.WriteLine("TestB");
            }
        }

        [TestMethod]
        [DataSource("CsvTestData32")]
        public void TestMethod1()
        {
            _testCount++;
            var testName = TestContext.DataRow["TestName"];
            Debug.Print("Test {0}: {1}", _testCount, testName);
        }

        [ClassCleanup]
        public static void ClassCleanup()
        {
            Assert.IsTrue(_classInitializeCalled);
            Assert.AreEqual(_testCount, 2);
            Debug.Print("Tests completed: Tests run {0}", _testCount);
        }
    }
}

In my case 'run test as 32-bit' is the default setting; this may be changed under -

  • in VS2012: TEST > TestSettings > Default Processor Architecture
  • in VS2010 Right-click Solution explorer 'Solution items' > Add > New Item > Test Settings, then,
  • VS2010 main menu > Tests > Edit Test Settings > Hosts > Run tests in 32 bit or 64 bit process.

If you use 64-bit, use [DataSource("CsvTestData64")], and you may need to install the MS Access 64-bit ODBC driver. The easiest way is to stick with 32-bit.

App.config

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
  <configSections>
    <section name="microsoft.visualstudio.testtools" type="Microsoft.VisualStudio.TestTools.UnitTesting.TestConfigurationSection, Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a" />
  </configSections>

  <microsoft.visualstudio.testtools>
    <dataSources>
      <add name="CsvTestData32" connectionString="CsvConn32" dataTableName="`TestList.csv`" dataAccessMethod="Sequential" />
      <add name="CsvTestData64" connectionString="CsvConn64" dataTableName="`TestTest.csv`" dataAccessMethod="Sequential" />
    </dataSources>
  </microsoft.visualstudio.testtools>

  <connectionStrings>
    <add name="CsvConn32" connectionString="Driver={Microsoft Text Driver (*.txt; *.csv)};.\;Extensions=csv;" providerName="System.Data.Odbc" />
    <add name="CsvConn64" connectionString="Driver={Microsoft Access Text Driver (*.txt, *.csv)};Dbq=.\;Extensions=csv" providerName="System.Data.Odbc" />
  </connectionStrings>
</configuration>
like image 408
Edward Avatar asked Oct 07 '22 00:10

Edward


1 Answers

MSTestHacks might help.

It allows an IEnumberable on your test class to be used as the DataSource for your TestMethod.

From the website:

Runtime DataSource

You MUST inherit your test class from TestBase

[TestClass]
public class UnitTest1 : TestBase
{ }

Create a Property, Field or Method, that returns an IEnumerable

[TestClass]
public class UnitTest1 : TestBase
{
    private IEnumerable<int> Stuff
    {
        get
        {
            //This could do anything, fetch a dynamic list from anywhere....
            return new List<int> { 1, 2, 3 };
        }
    }
}

Add the DataSource attribute to your test method, pointing back to the IEnumerable name created earlier. This needs to be fully qualified.

[TestMethod]
[DataSource("Namespace.UnitTest1.Stuff")]
public void TestMethod1()
{
    var number = this.TestContext.GetRuntimeDataSourceObject<int>();

    Assert.IsNotNull(number);
}
like image 182
Jon Avatar answered Oct 13 '22 09:10

Jon