NUnit will run all the tests using the same class instance, while xUnit will create a new instance for each test.
As far as NUnit vs. XUnit vs. MSTest is concerned, the biggest difference between xUnit and the other two test frameworks (NUnit and MSTest) is that xUnit is much more extensible when compared to NUnit and MSTest. The [Fact] attribute is used instead of the [Test] attribute.
If you have Visual Studio Community (or a paid-for version of Visual Studio), you can run your xUnit.net tests within Visual Studio's built-in test runner (named Test Explorer).
The main difference is the ability of MsTest to execute in parallel at the method level. Also, the tight integration of MsTest with Visual Studio provides advantages in both speed and robustness when compared to NUnit. As a result, I recommend MsTest.
xUnit offers a way to run parameterized tests through something called data theories. The concept is equivalent to the one found in NUnit but the functionality you get out of the box is not as complete.
Here's an example:
[Theory]
[InlineData("Foo")]
[InlineData(9)]
[InlineData(true)]
public void Should_be_assigned_different_values(object value)
{
Assert.NotNull(value);
}
In this example xUnit will run the Should_format_the_currency_value_correctly
test once for every InlineDataAttribute
each time passing the specified value as argument.
Data theories are an extensibility point that you can use to create new ways to run your parameterized tests. The way this is done is by creating new attributes that inspect and optionally act upon the arguments and return value of the test methods.
You can find a good practical example of how xUnit's data theories can be extended in AutoFixture's AutoData and InlineAutoData theories.
Let me throw one more sample here, just in case it saves some time to someone.
[Theory]
[InlineData("goodnight moon", "moon", true)]
[InlineData("hello world", "hi", false)]
public void Contains(string input, string sub, bool expected)
{
var actual = input.Contains(sub);
Assert.Equal(expected, actual);
}
On your first request, you can follow the examples found here.
You can construct a static class containing the data necessary for a collection of tests
using System.Collections.Generic;
namespace PropertyDataDrivenTests
{
public static class DemoPropertyDataSource
{
private static readonly List<object[]> _data = new List<object[]>
{
new object[] {1, true},
new object[] {2, false},
new object[] {-1, false},
new object[] {0, false}
};
public static IEnumerable<object[]> TestData
{
get { return _data; }
}
}
}
Then, using the MemberData attribute, define the test as such
public class TestFile1
{
[Theory]
[MemberData("TestData", MemberType = typeof(DemoPropertyDataSource))]
public void SampleTest1(int number, bool expectedResult)
{
var sut = new CheckThisNumber(1);
var result = sut.CheckIfEqual(number);
Assert.Equal(result, expectedResult);
}
}
or if you're using C# 6.0,
[Theory]
[MemberData(nameof(PropertyDataDrivenTests.TestData), MemberType = typeof(DemoPropertyDataSource))]
The first argument of MemberDataAttribute allows you to define the member you use as a datasource, so you have a fair amount of flexibility on reuse.
According to this article in xUnit you have three "parametrization" options:
InlineData example
[Theory]
[InlineData(1, 2)]
[InlineData(-4, -6)]
[InlineData(2, 4)]
public void FooTest(int value1, int value2)
{
Assert.True(value1 + value2 < 7)
}
ClassData example
public class BarTestData : IEnumerable<object[]>
{
public IEnumerator<object[]> GetEnumerator()
{
yield return new object[] { 1, 2 };
yield return new object[] { -4, -6 };
yield return new object[] { 2, 4 };
}
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
[Theory]
[ClassData(typeof(BarTestData))]
public void BarTest(int value1, int value2)
{
Assert.True(value1 + value2 < 7)
}
MemberData example
[Theory]
[MemberData(nameof(BazTestData))]
public void BazTest(int value1, int value2)
{
Assert.True(value1 + value2 < 7)
}
public static IEnumerable<object[]> BazTestData => new List<object[]>
{
new object[] { 1, 2 },
new object[] { -4, -6 },
new object[] { 2, 4 },
};
I found a library that produces equivalent functionality to NUnit's [Values]
attribute called Xunit.Combinatorial:
It allows you to specify parameter-level values:
[Theory, CombinatorialData]
public void CheckValidAge([CombinatorialValues(5, 18, 21, 25)] int age,
bool friendlyOfficer)
{
// This will run with all combinations:
// 5 true
// 18 true
// 21 true
// 25 true
// 5 false
// 18 false
// 21 false
// 25 false
}
Or you can implicitly have it figure out the minimal number of invocations to cover all possible combinations:
[Theory, PairwiseData]
public void CheckValidAge(bool p1, bool p2, bool p3)
{
// Pairwise generates these 4 test cases:
// false false false
// false true true
// true false true
// true true false
}
I took on-board all the answers here and additionally made use of XUnit's TheoryData<,>
generic types to give me simple, easy to read and type safe data definitions for the 'MemberData' attribute on my test, as per this example:
/// must be public & static for MemberDataAttr to use
public static TheoryData<int, bool, string> DataForTest1 = new TheoryData<int, bool, string> {
{ 1, true, "First" },
{ 2, false, "Second" },
{ 3, true, "Third" }
};
[Theory(DisplayName = "My First Test"), MemberData(nameof(DataForTest1))]
public void Test1(int valA, bool valB, string valC)
{
Debug.WriteLine($"Running {nameof(Test1)} with values: {valA}, {valB} & {valC} ");
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With