182

NUnit has a feature called Values, like below:

[Test]
public void MyTest(
    [Values(1,2,3)] int x,
    [Values("A","B")] string s)
{
    // ...
}

This means that the test method will run six times:

MyTest(1, "A")
MyTest(1, "B")
MyTest(2, "A")
MyTest(2, "B")
MyTest(3, "A")
MyTest(3, "B")

We're using MSTest now, but is there any equivalent for this so that I can run the same test with multiple parameters?

[TestMethod]
public void Mytest()
{
    // ...
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
The Light
  • 26,341
  • 62
  • 176
  • 258
  • You can use MSTestHacks, as described in http://stackoverflow.com/a/19536942/52277 answer. – Michael Freidgeim May 02 '16 at 22:28
  • Possible duplicate of [How to RowTest with MSTest?](http://stackoverflow.com/questions/347535/how-to-rowtest-with-mstest) – Michael Freidgeim May 02 '16 at 22:31
  • @MichaelFreidgeim This question has better answers than your suggested target – Rob May 02 '16 at 23:43
  • 1
    @Rob: IMHO, the most appropriate answer -MSTestHacks -[How to RowTest with MSTest?](http://stackoverflow.com/a/19536942) is missing in this question. – Michael Freidgeim May 03 '16 at 00:36
  • @MichaelFreidgeim Perhaps, though it appears that the functionality has existed for 3 1/2 years now (http://stackoverflow.com/questions/9021881/how-to-run-a-test-method-with-multiple-parameters-in-mstest/13710788#13710788) – Rob May 03 '16 at 00:46
  • @Rob: only available within the unit testing project for WinRT/Metro. See https://visualstudio.uservoice.com/forums/330519-team-services/suggestions/3865310-allow-use-of-datatestmethod-datarow-in-all-unit – Michael Freidgeim May 03 '16 at 04:16

9 Answers9

207

EDIT 4: Looks like this is completed in MSTest V2 June 17, 2016: https://blogs.msdn.microsoft.com/visualstudioalm/2016/06/17/taking-the-mstest-framework-forward-with-mstest-v2/

Original Answer:

As of about a week ago in Visual Studio 2012 Update 1 something similar is now possible:

[DataTestMethod]
[DataRow(12,3,4)]
[DataRow(12,2,6)]
[DataRow(12,4,3)]
public void DivideTest(int n, int d, int q)
{
  Assert.AreEqual( q, n / d );
}

EDIT: It appears this is only available within the unit testing project for WinRT/Metro. Bummer

EDIT 2: The following is the metadata found using "Go To Definition" within Visual Studio:

#region Assembly Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll, v11.0.0.0
// C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\MSTestFramework\11.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll
#endregion

using System;

namespace Microsoft.VisualStudio.TestPlatform.UnitTestFramework
{
    [AttributeUsage(AttributeTargets.Method, AllowMultiple = false)]
    public class DataTestMethodAttribute : TestMethodAttribute
    {
        public DataTestMethodAttribute();

        public override TestResult[] Execute(ITestMethod testMethod);
    }
}

EDIT 3: This issue was brought up in Visual Studio's UserVoice forums. Last Update states:

STARTED · Visual Studio Team ADMIN Visual Studio Team (Product Team, Microsoft Visual Studio) responded · April 25, 2016 Thank you for the feedback. We have started working on this.

Pratap Lakshman Visual Studio

https://visualstudio.uservoice.com/forums/330519-team-services/suggestions/3865310-allow-use-of-datatestmethod-datarow-in-all-unit

McAden
  • 13,714
  • 5
  • 37
  • 63
  • 4
    Windows Phone is now supported also, with Visual Studio 2012 Update 2 (currently, CTP 4) – Pedro Lamas Mar 14 '13 at 11:10
  • 9
    I have update 1 but DataTestMethod and DataRow are not recognised, which library are these attributes in? – DevDave Mar 27 '13 at 12:15
  • What type of project are you testing? – McAden Apr 06 '13 at 05:33
  • 3
    Is there any official source about DataTestMethod? What namespace is it in, which assembly? – Igor Lankin Apr 06 '13 at 21:15
  • 3
    I found that the UnitTestFramework.dll was installed on my computer and after manually referencing it I was able to write a method using the [DataTestMethod] attribute with data rows but I cannot get the Test Explorer in Visual Studio 2012.3 to find the method. – Josh DeLong Aug 07 '13 at 16:53
  • In a non windows-store project? – McAden Aug 07 '13 at 17:13
  • 5
    I went to the file path "C:\Program Files (x86)\Microsoft SDKs\Windows\v8.0\ExtensionSDKs\MSTestFramework\11.0\References\CommonConfiguration\neutral\Microsoft.VisualStudio.TestPlatform.UnitTestFramework.dll" on my computer and the file was there. So I referenced it in my basic unit test project. Opening the dll in JustDecompile shows that the library only has references to mscorlib, System, and System.Core. It's not a Windows Store project. – Josh DeLong Aug 07 '13 at 18:00
  • 1
    I've only been able to get it to work on Windows Store projects. – McAden Aug 07 '13 at 18:04
  • Can you specify expected result in `DataRow`? – Leonid Vasilev Feb 05 '17 at 09:32
  • The only way I'm aware of is to make it one of the arguments just like the example I gave in the answer. – McAden Feb 06 '17 at 17:28
  • I am using VS2017 and I found `DataTestMethod` in a nuget package I unfortunately can't remember the name of. What I did was to write `[DataTestMethod]` and then press `ctrl-.` to let VS install the nuget package. I then had to remove the old testing lib as there is a name clash. FWIW. – LosManos Jul 23 '18 at 21:55
71

This feature is in pre-release now and works with Visual Studio 2015.

For example:

[TestClass]
public class UnitTest1
{
    [TestMethod]
    [DataRow(1, 2, 2)]
    [DataRow(2, 3, 5)]
    [DataRow(3, 5, 8)]
    public void AdditionTest(int a, int b, int result)
    {
        Assert.AreEqual(result, a + b);
    }
}
Ambrose Leung
  • 3,704
  • 2
  • 25
  • 36
Pompair
  • 7,083
  • 11
  • 60
  • 69
  • 4
    This is the correct answer. Note that it is not necessary to say [DataTestMethod] to use [DataRow] (https://stackoverflow.com/a/59162403/2540235) – Design.Garden Feb 17 '20 at 18:50
  • 2
    This is the correct answer which shall be accepted! Really works for me! Thanks! – Anduin Xue Nov 18 '20 at 07:36
  • `[DataRow(1, 2, 3)]` ?? – JohnB Feb 02 '21 at 17:53
  • @JohnB presumably the arguments for `a`, `b`, and `result` respectively. – timelmer Apr 14 '21 at 21:09
  • 1
    I'm saying the first set of test data is wrong. I think it should be: `[DataRow(1, 2, 3)]` – JohnB Apr 15 '21 at 22:43
  • After I add the dll in your reference point, the dll conflict with my project reference `Microsoft.VisualStudio.QulityTools.UnitTestFrameWrok`, I remove it. And `DataRow` is accepted, but my Tests Explorer can't find the Tests. – Jun Yu Feb 23 '22 at 00:54
49

It is unfortunately not supported in older versions of MSTest. Apparently there is an extensibility model and you can implement it yourself. Another option would be to use data-driven tests.

My personal opinion would be to just stick with NUnit though...

As of Visual Studio 2012, update 1, MSTest has a similar feature. See McAden's answer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
jeroenh
  • 26,362
  • 10
  • 73
  • 104
  • We're using Selenium which generates NUnit code so we switched to use NUnit instead :) – The Light Jan 27 '12 at 11:53
  • 4
    I've found that something similar is now possible in Visual Studio 2012 Update 1, just FYI for future consideration of anybody looking at this answer. – McAden Dec 04 '12 at 19:53
  • @McAden do you have a link with an explanation? – jeroenh Dec 04 '12 at 22:10
  • 7
    I gave an answer below with an example and a link to my blog post. It mentions the attributes necessary and also the "DisplayName" property on the attribute that distinguishes the cases in the Test Explorer. It was also mentioned in the October announcment of the CTP (which now has the official release) http://blogs.msdn.com/b/visualstudioalm/archive/2012/10/26/final-ctp-for-visual-studio-2012-update-1.aspx I've added the information to this SO question because I spent quite a bit of time looking for it. Hopefully this will save somebody some time. – McAden Dec 04 '12 at 22:52
13

Not exactly the same as NUnit's Value (or TestCase) attributes, but MSTest has the DataSource attribute, which allows you to do a similar thing.

You can hook it up to database or XML file - it is not as straightforward as NUnit's feature, but it does the job.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
k.m
  • 30,794
  • 10
  • 62
  • 86
7

MSTest has a powerful attribute called DataSource. Using this you can perform data-driven tests as you asked. You can have your test data in XML, CSV, or in a database. Here are few links that will guide you

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pritam Karmakar
  • 2,773
  • 5
  • 30
  • 49
5

It's very simple to implement - you should use TestContext property and TestPropertyAttribute.

Example

public TestContext TestContext { get; set; }
private List<string> GetProperties()
{
    return TestContext.Properties
        .Cast<KeyValuePair<string, object>>()
        .Where(_ => _.Key.StartsWith("par"))
        .Select(_ => _.Value as string)
        .ToList();
}

//usage
[TestMethod]
[TestProperty("par1", "http://getbootstrap.com/components/")]
[TestProperty("par2", "http://www.wsj.com/europe")]
public void SomeTest()
{
    var pars = GetProperties();
    //...
}

EDIT:

I prepared few extension methods to simplify access to the TestContext property and act like we have several test cases. See example with processing simple test properties here:

[TestMethod]
[TestProperty("fileName1", @".\test_file1")]
[TestProperty("fileName2", @".\test_file2")]
[TestProperty("fileName3", @".\test_file3")]
public void TestMethod3()
{
    TestContext.GetMany<string>("fileName").ForEach(fileName =>
    {
        //Arrange
        var f = new FileInfo(fileName);

        //Act
        var isExists = f.Exists;

        //Asssert
        Assert.IsFalse(isExists);
    });
}

and example with creating complex test objects:

[TestMethod]
//Case 1
[TestProperty(nameof(FileDescriptor.FileVersionId), "673C9C2D-A29E-4ACC-90D4-67C52FBA84E4")]
//...
public void TestMethod2()
{
    //Arrange
    TestContext.For<FileDescriptor>().Fill(fi => fi.FileVersionId).Fill(fi => fi.Extension).Fill(fi => fi.Name).Fill(fi => fi.CreatedOn, new CultureInfo("en-US", false)).Fill(fi => fi.AccessPolicy)
        .ForEach(fileInfo =>
        {
            //Act
            var fileInfoString = fileInfo.ToString();

            //Assert
            Assert.AreEqual($"Id: {fileInfo.FileVersionId}; Ext: {fileInfo.Extension}; Name: {fileInfo.Name}; Created: {fileInfo.CreatedOn}; AccessPolicy: {fileInfo.AccessPolicy};", fileInfoString);
        });
}

Take a look to the extension methods and set of samples for more details.

Andrey Burykin
  • 700
  • 11
  • 23
5

I couldn't get The DataRowAttribute to work in Visual Studio 2015, and this is what I ended up with:

[TestClass]
public class Tests
{
    private Foo _toTest;

    [TestInitialize]
    public void Setup()
    {
        this._toTest = new Foo();
    }

    [TestMethod]
    public void ATest()
    {
        this.Perform_ATest(1, 1, 2);
        this.Setup();

        this.Perform_ATest(100, 200, 300);
        this.Setup();

        this.Perform_ATest(817001, 212, 817213);
        this.Setup();
    }

    private void Perform_ATest(int a, int b, int expected)
    {
        // Obviously this would be way more complex...

        Assert.IsTrue(this._toTest.Add(a,b) == expected);
    }
}

public class Foo
{
    public int Add(int a, int b)
    {
        return a + b;
    }
}

The real solution here is to just use NUnit (unless you're stuck in MSTest like I am in this particular instance).

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Brandon
  • 4,491
  • 6
  • 38
  • 59
  • 4
    you should split each test call to a separate test in order to save you time when one of them will break. (which we all know will happen) – silver Feb 08 '17 at 13:33
  • Yes, of course. In practice that's how it would be done. In this case I was just illustrating it for simplicity – Brandon Feb 08 '17 at 14:07
4

There is, of course, another way to do this which has not been discussed in this thread, i.e. by way of inheritance of the class containing the TestMethod. In the following example, only one TestMethod has been defined but two test cases have been made.

In Visual Studio 2012, it creates two tests in the TestExplorer:

  1. DemoTest_B10_A5.test
  2. DemoTest_A12_B4.test

    public class Demo
    {
        int a, b;
    
        public Demo(int _a, int _b)
        {
            this.a = _a;
            this.b = _b;
        }
    
        public int Sum()
        {
            return this.a + this.b;
        }
    }
    
    public abstract class DemoTestBase
    {
        Demo objUnderTest;
        int expectedSum;
    
        public DemoTestBase(int _a, int _b, int _expectedSum)
        {
            objUnderTest = new Demo(_a, _b);
            this.expectedSum = _expectedSum;
        }
    
        [TestMethod]
        public void test()
        {
            Assert.AreEqual(this.expectedSum, this.objUnderTest.Sum());
        }
    }
    
    [TestClass]
    public class DemoTest_A12_B4 : DemoTestBase
    {
        public DemoTest_A12_B4() : base(12, 4, 16) { }
    }
    
    public abstract class DemoTest_B10_Base : DemoTestBase
    {
        public DemoTest_B10_Base(int _a) : base(_a, 10, _a + 10) { }
    }
    
    [TestClass]
    public class DemoTest_B10_A5 : DemoTest_B10_Base
    {
        public DemoTest_B10_A5() : base(5) { }
    }
    
4

MSTest does not support that feature, but you can implement your own attribute to achieve that.

Have a look at Enabling parameterized tests in MSTest using PostSharp.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Massimiliano Peluso
  • 26,379
  • 6
  • 61
  • 70