Row Tests or Paramerterized Tests (MsTest) – Xml

In a previous post, I discussed Parameter Value Coverage (PVC). One of the easiest ways to add PVC to your test suite is to use Row Tests, sometimes called Parameterized Tests. Row test is the idea of writing a single unit test, but passing many different values in.

Different testing frameworks implement row tests differently.

MsTest uses an attribute called DataResourceAttribute. This supports anything from a csv, Excel file or xml, to a full-blown database.

For a single Unit Test, NUnit’s Row tests are far superior. However, for a larger test project, you will see that DataSourceAttribute with external data sources, scales nicely and compares to NUnits TestCaseSource. However, it is not as easy to get it right the first time. It needs a step by step tutorial.

Step 1 – Create a the Project

  1. In Visual Studio click File | New | Project.
  2. Select Unit Test Project for C#.
  3. Give it a name and a path and click OK.

Step 2 – Add an Xml file

  1. Create a folder in your visual studio project called Data.
  2. Right-click on the data folder and choose Add | New Item.
  3. Create new Xml file named: Data.xml
  4. Add the following to the Xml.
<?xml version="1.0" encoding="utf-8" ?>
<Rows xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:x="urn:Row">
  <!-- Schema -->
  <xsd:schema targetNamespace="urn:Row" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="Row">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element type="xsd:int" name="Value1"/>
          <xsd:element type="xsd:int" name="Value2"/>
          <xsd:element type="xsd:int" name="ExpectedValue"/>
          <xsd:element type="xsd:string" name="Message"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <!--End Schema-->
  <x:Row>
    <x:Value1>3</x:Value1>
    <x:Value2>2</x:Value2>
    <x:ExpectedValue>2</x:ExpectedValue>
    <x:Message>2 is less than 3</x:Message>
  </x:Row>
  <x:Row>
    <x:Value1>-1</x:Value1>
    <x:Value2>0</x:Value2>
    <x:ExpectedValue>-1</x:ExpectedValue>
    <x:Message>-1 less than 0</x:Message>
  </x:Row>
  <x:Row>
    <x:Value1>10</x:Value1>
    <x:Value2>5</x:Value2>
    <x:ExpectedValue>5</x:ExpectedValue>
    <x:Message>5 is less than 10</x:Message>
  </x:Row>
</Rows>

Note: This Xml is designed as such so the Schema is inline. That allows us to specify the data type.

Step 3 – Set Xml File Properties

The XML file needs to be copied on build.

  1. Right-click on the Xml file and choose Properties.
  2. Change the Copy to output directory to: Copy if newer

Step 4 – Add a Unit Test method

Note: We won’t have a real project to test. We will just test Math.Min() for an example.

  1. Add a reference to System.Data.
  2. Add the TestContext property. (See line 9 below)
  3. Add a DataSource attribute to the test method. (See line 12 below)
    Notice that is uses Row not Rows (it doesn’t use the root element but the second element).
  4. Use TestContext.DataRow[0] to get the first column. (See line 16 below)
    Note: You can also access the column by the column name we used: TestContext.DataRow[Value1]

  5. Assign variables for the rest of the columns. (See lines 16-19 below)
  6. Add the test and the assert. (See lines 22 and 25)
using System;
using Microsoft.VisualStudio.TestTools.UnitTesting;

namespace MsTestRowTestXml
{
    [TestClass]
    public class UnitTest1
    {
        public TestContext TestContext { get; set; }

        [TestMethod]
        [DataSource("Microsoft.VisualStudio.TestTools.DataSource.XML", @"Data\Data.xml", "Row", DataAccessMethod.Sequential)]
        public void TestMethod1()
        {
            // Arrange
            int a = (int)TestContext.DataRow[0];
            int b = (int)TestContext.DataRow[1];
            int expected = (int)TestContext.DataRow[2];
            string message = TestContext.DataRow[3].ToString();

            // Act
            var actual = Math.Min(a, b);

            // Assert
            Assert.AreEqual(expected, actual, message);
        }
    }
}

You finished! Good job!.

Use Common Xml files for Parameter Value Coverage

While this method involved way more steps than anything with NUnit to set up, tt can actually be a bit quicker for subsequent tests and quite useful when testing larger projects. Once you have the Xml files setup, you can reuse them for many methods. For example, for every method that takes a long, you could use the same DataSource to get Parameter Value Coverage (PVC).

<?xml version="1.0" encoding="utf-8" ?>
<Rows xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xmlns:x="urn:Row">
  <!-- Schema -->
  <xsd:schema targetNamespace="urn:Row" attributeFormDefault="unqualified" elementFormDefault="qualified" xmlns:xsd="http://www.w3.org/2001/XMLSchema" >
    <xsd:element name="Row">
      <xsd:complexType>
        <xsd:sequence>
          <xsd:element type="xsd:long" name="Value"/>
          <xsd:element type="xsd:string" name="Message"/>
        </xsd:sequence>
      </xsd:complexType>
    </xsd:element>
  </xsd:schema>
  <!--End Schema-->
  <x:Row>
    <x:Value>2147483648</x:Value>
    <x:Message>One more than int.MaxValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-2147483649</x:Value>
    <x:Message>One less than int.MinValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>9223372036854775807</x:Value>
    <x:Message>long.MaxValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-9223372036854775808</x:Value>
    <x:Message>long.MinValue</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>0</x:Value>
    <x:Message>0 (zero)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>1</x:Value>
    <x:Message>1 (one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>2</x:Value>
    <x:Message>2 (one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-1</x:Value>
    <x:Message>-1 (minus one)</x:Message>
  </x:Row>
  <x:Row>
    <x:Value>-2</x:Value>
    <x:Message>-2, -2 (minus one)</x:Message>
  </x:Row>
</Rows>

3 Comments

  1. Geeta says:

    Hi,
    I am new to unit testing.

    I have a query related to mocking up data :

    If we are using xml or csv to mock data, for multiple scenarios we need to multiple files or in single xml file we need to dump all the possible test data?

Leave a Reply

How to post code in comments?