Unit testing with xUnit.net

Updated 15/09/2023

xUnit.net is a free, open source, community-focused unit testing tool for the .NET Framework. Install xunit from Nuget as version 2.4.1.

Fact

See Testing Strategies to understand what U_I_E is.

1
2
3
4
5
6
7
8
9
10
11
[Fact]
public void U_I_E()
{
// Arrange

// Act
var someBool = ...

// Assert
Assert.Equal(shouldPass, someBool>);
}

Other asserts

1
2
3
4
Assert.Contains(collection, x => x.SweetProp == "Foo");
Assert.DoesNotContain(collection, x => x.SweetProp == "Bar");
Assert.NotNull(fooObj);
Assert.True(condition);

Theory - Inline Data

1
2
3
4
5
6
7
8
9
10
11
12
13
[Theory]
[InlineData("foo@bar.com", true)]
[InlineData("baz@bat.com", false)]
public void U_I_E(string someEmail, bool someBool)
{
// Arrange

// Act
var someBool = ...

// Assert
Assert.Equal(shouldPass, someBool>);
}

Theory - Member Data

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public static IEnumerable<object[]> FooTestData()
{
// someString, someStrings
yield return new object[] { "foo", new[] { "aaa", "bbb" } };
yield return new object[] { "bar", new[] { "ccc", "ddd" } };
}

[Theory]
[MemberData(nameof(FooTestData))]
public void U_I_E(string someString, IEnumerable<string> someStrings)
{
// Arrange

// Act

// Assert
Assert.Equal(...
}

Shared Context between Tests

xUnit doesnt have explicit [SetUp] and [TearDown] annotations like NUnit, instead they say you must use a Constructor and Dispose.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class StackTests : IDisposable
{
Stack<int> stack;

public StackTests()
{
stack = new Stack<int>();
}

public void Dispose()
{
stack.Dispose();
}

....
}

Exceptions

Verifies that the exact exception is thrown (and not a derived exception type). Returns the exception that was thrown, when successful.

1
2
3
4
5
// Act
var exception = Assert.ThrowsAsync<HttpRequestException>(async () => await classUnderTest.SomeMethodThatThrowsAsync());

// Assert
Assert.Equal(expectedExceptionMessage, exception.Result.Message);

Naming rules

Define conventions across project from this post

1
2
3
4
5
6
7
8
9
10
11
12
13
[Fact]
public void DomainEvent_Should_Have_DomainEventSuffix
{
var result = Types
.InAssembly(DomainAssembly)
.That()
.ImplementInterface(typeof(IDomainEvent))
.Should()
.HaveNameEndingWith("DomainEvent")
.GetResult();

result.IsSuccessful.Should().BeTrue();
}

Architecture tests

  • Enforce command handler naming
1
2
3
4
5
6
7
8
9
10
11
12
13
14
[Fact]
public void CommandHandler_Should_HaveNameEndingWith_CommandHandler
{
var result = Types.InAssembly(ApplicationAssembly)
.That()
.ImplementInterface(typeof(ICommandHandler<>))
.Or()
.ImplementInterface(typeof(ICommandHandler<,>))
.Should()
.HaveNameEndingWith("CommandHandler")
.GetResult();

result.IsSuccessful.Should().BeTrue();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[Fact]
public void DomainLayer_Should_NotHaveDependencyOn_ApplicationLayer()
{
var result = Types.InAssembly(DomainAssembly)
.Should()
.NotHaveDepencyOn(ApplicationAssembly.GetName().Name)
.GetResult();

result.IsSuccessful.Should().BeTrue();
}

[Fact]
public void DomainLayer_Should_NotHaveDependcyOn_InfrastructureLayer()
{
var result Types.InAssembly(DomainAssembly)
.Should()
.NotHaveDepencyOn(InfrastructureAssembly.GetName().Name)
.GetResult();

result.IsSuccessful.Should().BeTrue();
}

References