Saturday, September 15, 2012

Data Driven Unit Testing with XML

I had been stopped writing blog for the past 3 months, it is really tough for me to keep up the momentum in writing blog in a timely manner. Well, until recently I join a new company and I suppose I will encounter some unfamiliar issue and new experience to share here more oftenly.

Back to the topic, I would like to share how to write data driven unit test with XML.

Do you ever encounter a scenario that you wish to test one test case with multiple different set of test data?

I used to experience in writing data driven unit test with MbUnit. But, today I want to share about doing the same thing with Visual Studio unit test.
Here is one of the solution with XML.

        [DeploymentItem("\\TestData\\TimeOffTestData.xml"), TestMethod()]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
            "|DataDirectory|\\TestData\\TimeOffTestData.xml", 
            "TimeOffTest_ApplyTimeOffTest", DataAccessMethod.Sequential)]
        public void ApplyTimeOffTest()
        {
            TimeOff timeOff = new TimeOff();
            timeOff.UserId = int.Parse(TestContext.DataRow["UserID"].ToString());
            timeOff.StartDate = DateTime.Parse(TestContext.DataRow["StartDate"].ToString());
            timeOff.EndDate = DateTime.Parse(TestContext.DataRow["EndDate"].ToString());

            TimeOffComponent component = new TimeOffComponent();

            try
            {
                component.Apply(timeOff);
            }
            catch (Exception ex)
            {
                if (!Convert.ToBoolean(TestContext.DataRow["ExpectException"]))
                {
                    throw ex;
                }
                else
                {
                    Assert.AreEqual(typeof(InvalidTimeOffException), ex.GetType(), 
                        "This exception type was unexpected.");
                }
            }
        }
Here is the content of my test data XML:
  
<?xml version="1.0" encoding="utf-8" ?>
<TestData>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-09-10</StartDate>
    <EndDate>2012-09-13</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-11-13</StartDate>
    <EndDate>2012-11-10</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-11-12</StartDate>
    <EndDate>2012-11-13</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
  <TimeOffTest_ApplyTimeOffTest>
    <UserID>1</UserID>
    <StartDate>2012-11-15</StartDate>
    <EndDate>2012-11-20</EndDate>
    <ExpectException>true</ExpectException>
  </TimeOffTest_ApplyTimeOffTest>
</TestData>

What's does Microsoft.VisualStudio.TestTools.DataSource.XML do at the background is above XML will be parsed into a table, hence <TimeOffTest_ApplyTimeOffTest> is a table name then its child elements are columns name then the element content are the row data. Therefore above XML describe 4 set of test data and the differences of the test data.

When you perform test run, it will perform 4 runs with different set of test data accordingly to the defined XML above.

Here is how the test result look like:



Common Problem

After you have finished coding, and you could not get the same result like above screenshot. Following are the common issues that you may encounter and here is the solution:

Known Issue: The unit test adapter failed to connect to the data source or read the data.


Resolution:

Go to your Solution Explorer, add new item to your solution, then select "Test Settings" from the left menu, then add a new test setting.


In the "Test Settings" window, select "Deployment" from the left menu, then check the "Enable Deployment" checkbox.



If problem still persist, go to Solution Explorer, locate your test data XML file and then open the file properties. Make sure the "Copy to Output Directory" property is NOT set to "Do not copy", make it either "Copy always" or "Copy if newer".



If problem still persist and you are using Visual Studio 2012, move your XML file to your project root directory. The problem is the |Data Directory| is not returning correct path. I notice some odd behavior between Visual Studio 2010 and 2012.

I have a folder call "TestData" that keep all my XML files in my test project well organized.

With Visual Studio 2010, no issue in detecting my XML file in the folder.
With Visual Studio 2012, I will get the error. However, there is a workaround for it, which is not to use |Data Directory| when specifying your test data file location. Instead, use real physical path. For example:

        [DeploymentItem("\\TestData\\TimeOffTestData.xml"), TestMethod()]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML",
            "D:\\Projects\\DataDrivenUnitTest\\DataDrivenUnitTest.Test\\TestData\\TimeOffTestData.xml", 
            "TimeOffTest_ApplyTimeOffTest", DataAccessMethod.Sequential)]
        public void ApplyTimeOffTest()


There is one more workaround for solving the problem with |DataDirectory| in Visual Studio 2012. You can set Copy to Output Directory value to "Do not copy" for the XML file. Then, open the unit test project properties, then set the post-build event command line: copy "$(ProjectDir)TestData" "$(ProjectDir)$(OutDir)"



So that, every time you build your unit test project, the command line above copy all the files in the TestData folder to your output directory without the TestData folder automatically.



You may download my unit test project to play around: Download Here


10 comments:

  1. Thank you for the Visual Studio 2012 workarounds!

    ReplyDelete
    Replies
    1. Sylvester'S Knowledge Base: Data Driven Unit Testing With Xml >>>>> Download Now

      >>>>> Download Full

      Sylvester'S Knowledge Base: Data Driven Unit Testing With Xml >>>>> Download LINK

      >>>>> Download Now

      Sylvester'S Knowledge Base: Data Driven Unit Testing With Xml >>>>> Download Full

      >>>>> Download LINK hA

      Delete
  2. Thank you. Finally someone that actually is experiencing the same thing I am. I had resolved myself to keeping everything in the root folder. Thanks for the post build work-around!

    I just lost 2 hours I will never get back trying to figure this out!

    ReplyDelete
  3. what's the password of the zip? Thanks.

    ReplyDelete
    Replies
    1. Hi, try to download again, I have removed the password.

      Delete
  4. Hi Seng, in VS 2013 I got this error:
    Error details: The 'Microsoft.VisualStudio.TestTools.DataSource.XML' provider is not registered on the local machine.

    How do you fix this error?

    Thanks

    ReplyDelete
  5. No worry Seng, problem solved. Do not use the connection string constructor.

    ReplyDelete
  6. I am using [DataSource(dataProvider,connectionString, dataAccessMethod)] method and facing problem while retrieving single value from xml,
    It just working fine with two or more values. can u please help me .

    ReplyDelete
  7. Quick question: Is it possible to have multiple "tables" in the XML?

    ReplyDelete
  8. Sylvester'S Knowledge Base: Data Driven Unit Testing With Xml >>>>> Download Now

    >>>>> Download Full

    Sylvester'S Knowledge Base: Data Driven Unit Testing With Xml >>>>> Download LINK

    >>>>> Download Now

    Sylvester'S Knowledge Base: Data Driven Unit Testing With Xml >>>>> Download Full

    >>>>> Download LINK LL

    ReplyDelete

Send Transactional SMS with API

This post cover how to send transactional SMS using the Alibaba Cloud Short Message Service API. Transactional SMS usually come with One Tim...