Getting started with XUnit

Getting started with XUnit

I’ve worked with MSTest and NUnit previously, but for whatever reason not with xUnit. Thankfully, coming from either framework seemed to translate pretty easily into xUnit.

In the recent post I did:

Your favorite/most useful extension methods?

I explored working with xUnit for the first time, to help to ensure the extension methods I was implementing were working as I intended. Though I had written previously about the extension methods, I hadn’t covered the testing of them; I thought that deserved its own post.

What is unit testing?

If you’ve never worked with unit testing before, wikipedia describes them as:

In computer programming, unit testing is a software testing method by which individual units of source code, sets of one or more computer program modules together with associated control data, usage procedures, and operating procedures, are tested to determine whether they are fit for use.[1]

The way I usually describe it is: unit testing is the process of ensuring expected outcomes from a piece of code — ideally a single function — without relying on external resources. When unit testing, anything that’s needed outside of the method under test should be provided via an abstraction, rather than concretion — to ensure that you are testing only the method under test. The dependencies needed by the method can be provided by making use of mocks, fakes, and/or stubs — pieces of code programmed to exhibit specific behavior to help cover all potential “branches” within your code.

MSTest, nUnit, and xUnit differences

Not having worked with MSTest since prior to it allowing multiple testing scenarios to a single test, I wasn’t sure how to describe the differences. Luckily, a quick google search pointed me to a “differences” page written up on the xUnit site:

Comparing xUnit.net to other frameworks > xUnit.net

It appears that all the frameworks do the same thing more or less; though I find it interesting that .net core seems to pretty extensively use xUnit over their own testing framework of MSTest.

Project Setup

Thankfully, there is a project template (at least with whatever VS install options I used) to create an xUnit test project. If you do not have this, you just need to add the following NuGet packages to a project:

  • Microsoft.NET.Test.Sdk
  • xunit
  • xunit.runner.visualstudio

Your csproj file should look like this(ish):

gist

Testing a method

I picked a method from my extension methods post, that would allow me to make use of various types of using xUnit:

  • Fact — this piece of code does [this] thing
  • Theory — this piece of code does [this] thing, and here are multiple examples of that occurring with separate data driven tests.
  • Expected Exception — this type of test is checking the code throws an exception of an expected type.

The method we’ll be testing with is:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
/// <summary>
/// Attempts to find the first item in <see cref="items"/>
/// meeting <see cref="Predicate{T}"/>.
///
/// Returns the <see cref="true"/> when item found,
/// <see cref="false"/> when not.
///
/// Found result is contained within out parameter <see cref="result"/>.
/// </summary>
/// <typeparam name="T"></typeparam>
/// <param name="items"></param>
/// <param name="predicate"></param>
/// <param name="result"></param>
/// <returns><see cref="true"/> when item found. <see cref="false"/> otherwise.</returns>
/// <exception cref="ArgumentNullException">
/// Thrown when <see cref="items"/> or <see cref="Predicate{T}"/> is null.
/// </exception>
public static bool TryFirst<T>(
this IEnumerable<T> items,
Func<T, bool> predicate,
out T result
)
{
if (items == null)
throw new ArgumentNullException(nameof(items));
if (predicate == null)
throw new ArgumentNullException(nameof(predicate));

result = default(T);
foreach (var item in items)
{
if (predicate(item))
{
result = item;
return true;
}
}
return false;
}

The above extension method exists on IEnumerable<T> and works very similar to built in methods like int.TryParse(...). This method returns true/false depending on whether or not an item is found based on the predicate, and that item is then contained within the out parameter of result.

How can we test this? What in this method can be tested? Here are some of the things that can be tested:

  • ArgumentNullException if items is null.
  • ArgumentNullException if predicate is null
  • false when no item is found matching the predicate
  • true when an item is found matching the predicate
  • result contains the found item that met the predicate

Test class setup

Let’s start with our test class:

1
2
3
4
public class EnumerableExtensionTests
{

}

One thing I like about xUnit over nUnit, is that I don’t need to decorate the class in any way to indicate it is a class with unit tests. We’ll need (or rather, I’d like) a class to play around with, since our extension method works on a generic IEnumerable<T>. We can introduce a little fake class for testing purposes by updating our test class to:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
public class EnumerableExtensionTests
{
public class EnumerableTest
{
public int SomeInt { get; set; }
}

public static List<object[]> EnumerableTestData =>
new List<object[]>()
{
new object[]
{
new List<EnumerableTest>()
{
new EnumerableTest() { SomeInt = 1 },
new EnumerableTest() { SomeInt = 42 },
}
}
};
}

In the above, I’m defining a new type, to be used only by this test class, that has a property of SomeInt. Additionally, I set up some static data we will be using shortly to help ensure our method is working properly.

Let’s get into the tests

We have two ways our extension method can throw an ArgumentNullException — when either items or predicate is null. Let’s see what tests for those conditions can look like.

  • ArgumentNullException if items is null.
1
2
3
4
5
6
7
8
9
[Fact]
public void ShouldThrowWhenItemsNull()
{
List<EnumerableTest> items = null;

Assert.Throws<ArgumentNullException>(() =>
items.TryFirst(t => t.SomeInt == 42, out var result)
);
}

In the above, we’re setting up our IEnumerable<T> to be null, covering one of our branches in our method — this tests that when the items are null, an ArgumentNullException is thrown. NUnit decorated tests as [Test], here the test (in xUnit) is decorated as [Fact].

  • ArgumentNullException if predicate is null
1
2
3
4
5
6
7
8
[Theory]
[MemberData(nameof(EnumerableTestData))]
public void ShouldThrowWhenPredicateNull(List<EnumerableTest> items)
{
Assert.Throws<ArgumentNullException>(() =>
items.TryFirst(null, out var result)
);
}

In the above, I’m using a [Theory] rather than [Fact] — I’m not sure that I have to in this case, but from my NUnit days, I couldn’t instantiate instances of non primitives within an attribute, though I’m not sure if that’s a limitation of NUnit, or c#. Anyway, in this test I’m providing the sample data to the method that was defined in the test class definition, and then providing a null predicate; the second condition for throwing a ArgumentNullException.

  • false when an no item is found meeting the predicate

In this test, we want to provide a valid IEnumerable<T> to the extension method, with a valid predicate; though in this case our predicate is not a match on any item within items.

1
2
3
4
5
6
7
8
9
10
[Theory]
[MemberData(nameof(EnumerableTestData))]
public void ShouldReturnFalseWhenDataNotFound(List<EnumerableTest> items)
{
var found = items.TryFirst(
t => t.SomeInt == 100, out var result
);

Assert.False(found);
}

In the above, we’re making sure that the boolean returned from our function is false, since 100 does not exist within our sample data.

  • true when an item is found meeting the predicate

Next, we’ll make sure that the result of the extension method is true when the predicate matches an item within the items.

1
2
3
4
5
6
7
8
9
10
[Theory]
[MemberData(nameof(EnumerableTestData))]
public void ShouldReturnTrueWhenDataFound(List<EnumerableTest> items)
{
var found = items.TryFirst(
t => t.SomeInt == 42, out var result
);

Assert.True(found);
}

The above is really similar to the false test, except we’re providing a valid predicate that does match an item within items.

  • result contains the found item that met the predicate

Our final test, ensures that we retrieve the item in the out results parameter from the function:

1
2
3
4
5
6
7
8
9
10
11
12
[Theory]
[MemberData(nameof(EnumerableTestData))]
public void ShouldReturnDataWhenDataFound(List<EnumerableTest> items)
{
var dataToSearch = 42;

var found = items.TryFirst(
t => t.SomeInt == dataToSearch, out var result
);

Assert.Equal(dataToSearch, result.SomeInt);
}

It looks like this when running our tests:

xUnit and nUnit seem to be pretty similar in syntax and structure, though I do enjoy the notion of using constructors for test class setup, rather than SetUp as with nUnit.

The code from this post can be found:

Kritner-Blogs/ExtensionMethods

Related:

Author

Russ Hammett

Posted on

2018-12-06

Updated on

2022-10-13

Licensed under

Comments