Overview [ Documentation]
See also: https://xunit.net/#documentation
xUnit unit tests are created with dotnet new xunit -o TestProjectName
.
xUnit Attributes
Fact
Used to declare a test method that is run by the test runner:
using Xunit;
using Prime.Services;
namespace Prime.UnitTests.Services;
public class PrimeService_IsPrimeShould
{
[Fact]
public void IsPrime_InputIs1_ReturnFalse()
{
var primeService = new PrimeService();
bool result = primeService.IsPrime(1);
Assert.False(result, "1 should not be prime");
}
}
Theory
and InlineData
These attributes work together to test multiple values. Instead of the above IsPrime_InputIs1_ReturnFalse
method, consider:
namespace Prime.UnitTests.Services;
public class PrimeService_IsPrimeShould
{
private readonly PrimeService _primeService;
public PrimeService_IsPrimeShould() // <-- Test class constructor
{
_primeService = new PrimeService();
}
[Theory]
[InlineData(-1)]
[InlineData(0)]
[InlineData(1)]
// These attributes pass the values in the InlineData attributes to the value parameter of the test method:
public void IsPrime_ValuesLessThan2_ReturnFalse(int value)
{
var result = _primeService.IsPrime(value);
Assert.False(result, $"{value} should not be prime");
}
}
See here for a complete code sample.
Unit Testing with XUnit and Moq
dotnet new XUnit
dotnet add project moq
(in XUnit project)In XUnit project, add project reference to code project
Create the necessary mocks (like
PieRepository
,CategoryRepository
) withmoq.Mock
static method:public class RepositoryMocks { public static Mock<IPieRepository> GetPieRepository() { var pies = new List<Pie>() { new Pie() { … }, … } var mockPieRepository = new Mock<IPieRepository>(); // Mock _pieRepository.AllPies call mockPieRepository.Setup(repo => repo.AllPies).Returns(pies); // Mock _pieRepository.PiesOfTheWeek call mockPieRepository.Setup(repo => repo.PiesOfTheWeek).Returns(pies.Where(p => p.IsPieOfTheWeek)); // Mock _pieRepository.GetPieById(int) call by confirming the parameter is an int and returning pies[0]: mockPieRepository.Setup(repo => repo.GetPieById(It.IsAny<int>())).Returns(pies[0]); return mockPieRepository; } }
Write the tests
public class PieControllerTests { [Fact] // define this method as a fact that should be run by the test runner public void List_EmptyCategory_ReturnAllPies() { // arrange: var mockPieRepository = RepositoryMocks.GetPieRepository(); var mockCategoryRepository = RepositoryMocks.GetCategoryRepository(); var mockPieController = new PieController(mockPieRepository.Object, mockCategoryRepository.Object); // act: var result = mockPieController.List(""); // assert: // assert that the return value is of type ViewResult var viewResult = Assert.IsType<ViewResult>(result); // assert that the passed in viewmodel is of type PieListViewModel var pieListViewModel = Assert.IsAssignableFrom<PieListViewModel>(viewResult.ViewData.Model); // assert there are exactly 10 pies in the PieListViewModel Assert.Equal(10, pieListViewModel.Pies.Count()); } }
Run the tests:
dotnet test
or Tests > Run All Tests