Skip to content
Bruno Sonnino
Menu
  • Home
  • About
Menu

Parametrized tests with MS-Test

Posted on 18 March 2017

Recently, Microsoft introduced the new version of its test framework, MS-Test 2. With this new version, they introduced a new feature that I was waiting for a long time: parametrized tests (yes, NUnit and XUnit have had this for a long time, I know).

And what are parametrized tests? Let me show you with an example. Let’s say we have this routine to return Fibonacci numbers (source: )

public static int Fibonacci(int n)
{
    int a = 0;
    int b = 1;
    // In N steps compute Fibonacci sequence iteratively.
    for (int i = 0; i < n; i++)
    {
        int temp = a;
        a = b;
        b = temp + b;
    }
    return a;
}
C#

And we want to test it. We would like to test it with the numbers 0, 1, 2 and 80 (the first two are special cases, the third is a normal case and 80 is a large number to be sure that the routine works with large numbers). We should create a test like this:

[TestMethod]
public void Given0FibonacciReturns0()
{
   var fib = new Fib();
    var actual = fib.Fibonacci(0);
    Assert.AreEqual(0,actual);
}
C#

This is not a bad test, but we must copy and paste to test the other results. You may argue that we could create a test like this one:

[TestMethod]
public void GivenDataFibonacciReturnsResultsOk()
{
    var numbers = new[] { 0, 1, 2, 80 };
    var results = new[] { 0L, 1L, 1L, 23416728348467685L };
    var fib = new Fib();
    for (int i = 0; i < numbers.Length; i++)
    {
        var actual = fib.Fibonacci(numbers[i]);
        Assert.AreEqual(results[i], actual);
    }
}
C#

But this has some problems:

  • If a test fails, it’s difficult to know which number failed
  • If one number fails, the next ones are not tested
  • You don’t have a clear view of what is being tested

MS-Test has had for a long time Data Driven tests (), but this is very cumbersome. You must create a data file, assign it to the test and run the test using the TestContext. It’s too much work for just four tests, no?

Then it comes MS-Test 2. With it, you can create a DataTestMethod, with DataRows for each test. Let’s see how do you create a test with this new feature.

Creating Parametrized tests with MS-Test 2

In Visual Studio, create a new Console Project. In this project, create a new class and name it Fib.cs. Add this code to the class:

 public class Fib
 {
     public int Fibonacci(int n)
     {
         int a = 0;
         int b = 1;
         // In N steps compute Fibonacci sequence iteratively.
         for (int i = 0; i < n; i++)
         {
             int temp = a;
             a = b;
             b = temp + b;
         }
         return a;
     }
 }
C#

Then, in the solution, add a new Class Library project. Right click the References node in the Solution Explorer and add a reference to the console project. Then right click in the References node again and select “Manage NuGet packages”. Add the packages MsTest.TestAdapter and MsTest.TestFramework.

With that, you have a test project with MS-Test 2. If you are using Visual Studio 2017, the Test Project template already includes these two packages, but you must update them to the latest version, as the parametrized tests didn’t run well with the default packages.

Then, we can create our test:

[TestClass]
public class FibonacciTests
{
    [DataRow(0, 0)]
    [DataRow(1, 1)]
    [DataRow(2, 1)]
    [DataRow(80, 23416728348467685)]
    [DataTestMethod]
    public void GivenDataFibonacciReturnsResultsOk(int number, Int64 result)
    {
        var fib = new Fib();
        var actual = fib.Fibonacci(number);
        Assert.AreEqual(result, actual);
    }
}
C#

The test is very similar to the ones we are used to create, it just has some differences:

  • Instead of the TestMethod attribute, it is decorated with the DataTestMethod attribute
  • The method receives two parameters
  • Each test has a DataRow attribute associated to it.

If we run this test, we get these results:

As you can see, we have three tests that passed and one that failed. We didn’t take in account in our routine that the results could be very large and overflow. So, we must change the routine to take this in account:

public Int64 Fibonacci(int n)
{
    Int64 a = 0;
    Int64 b = 1;
    // In N steps compute Fibonacci sequence iteratively.
    for (int i = 0; i < n; i++)
    {
        Int64 temp = a;
        a = b;
        b = temp + b;
    }
    return a;
}
C#

Now, when you run the tests, you get this:

All tests are passing, and we can have a clear view of which tests were run, without the need of extra files or any other tricks. Cool, no? This was a very welcome addition to MS-Test and can improve a lot our testing.

The source code for this article is in https://github.com/bsonnino/Fibonacci

5 thoughts on “Parametrized tests with MS-Test”

  1. Sameer Arora says:
    8 February 2018 at 00:53

    Thanks for sharing more details. However, is there a way to actually reflect the input parameters in the test name that appears in the results. All we see is “Data Row 0”, “Data row 1” suffix, which is quite unhelpful to quickly tell for which parameters the test failed, and how to track such failures across daily run.

    This sounds like a basic usability thing that should be supported AND documented if it supported or not.

    Reply
    1. bsonnino says:
      9 February 2018 at 13:16

      Actually, the tests results show the parameters passed in VS 2017. Take a look at my results:

      Test Name: GivenDataFibonacciReturnsResultsOk
      Test FullName: Fibonacci.Tests.FibonacciTests.GivenDataFibonacciReturnsResultsOk
      Test Source: D:\Documentos\Artigos\Artigos\CSharp\ParametrizedTests\Fibonacci\Fibonacci.Tests\FibonacciTests.cs : line 15
      Test Outcome: Passed
      Test Duration: 0:00:00.0407585

      Result1 Name: GivenDataFibonacciReturnsResultsOk (0,0)
      Result1 Outcome: Passed
      Result1 Duration: 0:00:00.0407386
      Result1 StackTrace:
      Result1 Message:
      Result1 StandardOutput:
      Result1 StandardError:

      Result2 Name: GivenDataFibonacciReturnsResultsOk (1,1)
      Result2 Outcome: Passed
      Result2 Duration: 0:00:00.0000164
      Result2 StackTrace:
      Result2 Message:
      Result2 StandardOutput:
      Result2 StandardError:

      Result3 Name: GivenDataFibonacciReturnsResultsOk (2,1)
      Result3 Outcome: Passed
      Result3 Duration: 0:00:00.0000021
      Result3 StackTrace:
      Result3 Message:
      Result3 StandardOutput:
      Result3 StandardError:

      Result4 Name: GivenDataFibonacciReturnsResultsOk (80,23416728348467685)
      Result4 Outcome: Passed
      Result4 Duration: 0:00:00.0000014
      Result4 StackTrace:
      Result4 Message:
      Result4 StandardOutput:
      Result4 StandardError:

      If you want to know more if the test fails, you can use the assert message, like in

      Assert.AreEqual(result, actual,0.1,$”Test for {number}”);

      Reply
  2. Javier says:
    20 April 2018 at 13:27

    Sadly, that is not the case if you are using arrays (other collections?), you just get MyTest(A[], B[])

    Reply
  3. Javier says:
    20 April 2018 at 13:30

    A simple solution is to add a “fake” key tag (string) to each row BTW …

    Reply
  4. Monger39 says:
    16 July 2019 at 09:07

    It would be great to also use the ‘ExpectedException’ for parameterized tests,
    such that for specifically indicated ‘DataRow’s we can check if the expected
    exception is thrown…

    Reply

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

  • May 2025
  • December 2024
  • October 2024
  • August 2024
  • July 2024
  • June 2024
  • November 2023
  • October 2023
  • August 2023
  • July 2023
  • June 2023
  • May 2023
  • November 2022
  • October 2022
  • September 2022
  • August 2022
  • June 2022
  • April 2022
  • March 2022
  • February 2022
  • January 2022
  • July 2021
  • June 2021
  • May 2021
  • April 2021
  • March 2021
  • February 2021
  • January 2021
  • December 2020
  • October 2020
  • September 2020
  • April 2020
  • March 2020
  • January 2020
  • November 2019
  • September 2019
  • August 2019
  • July 2019
  • June 2019
  • April 2019
  • March 2019
  • February 2019
  • January 2019
  • December 2018
  • November 2018
  • October 2018
  • September 2018
  • August 2018
  • July 2018
  • June 2018
  • May 2018
  • November 2017
  • October 2017
  • September 2017
  • August 2017
  • June 2017
  • May 2017
  • March 2017
  • February 2017
  • January 2017
  • December 2016
  • November 2016
  • October 2016
  • September 2016
  • August 2016
  • July 2016
  • June 2016
  • May 2016
  • April 2016
  • March 2016
  • February 2016
  • October 2015
  • August 2013
  • May 2013
  • February 2012
  • January 2012
  • April 2011
  • March 2011
  • December 2010
  • November 2009
  • June 2009
  • April 2009
  • March 2009
  • February 2009
  • January 2009
  • December 2008
  • November 2008
  • October 2008
  • July 2008
  • March 2008
  • February 2008
  • January 2008
  • December 2007
  • November 2007
  • October 2007
  • September 2007
  • August 2007
  • July 2007
  • Development
  • English
  • Português
  • Uncategorized
  • Windows

.NET AI Algorithms asp.NET Backup C# Debugging Delphi Dependency Injection Desktop Bridge Desktop icons Entity Framework JSON Linq Mef Minimal API MVVM NTFS Open Source OpenXML OzCode PowerShell Sensors Silverlight Source Code Generators sql server Surface Dial Testing Tools TypeScript UI Unit Testing UWP Visual Studio VS Code WCF WebView2 WinAppSDK Windows Windows 10 Windows Forms Windows Phone WPF XAML Zip

  • Entries RSS
  • Comments RSS
©2025 Bruno Sonnino | Design: Newspaperly WordPress Theme
Menu
  • Home
  • About