When writing my unit tests I typically use the AAA(Arrange-Act-Assert) pattern. This pattern splits a test in 3 sections:
- The Arrange section of a unit test method initializes objects and sets the value of the data that is passed to the method under test.
- The Act section invokes the method under test with the arranged parameters.
- The Assert section verifies that the action of the method under test behaves as expected.
Here is an example from one of my projects using XUnit:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Fact] | |
public void GetAllCustomers_Returns_Multiple_Customers() | |
{ | |
//Arrange | |
var unitOfWorkFactory = _container.GetRequiredService<IUnitOfWorkFactory>(); | |
var repository = _container.GetRequiredService<CustomerRepository>(); | |
//Act | |
using var uow = unitOfWorkFactory.Create(); | |
var customers = repository.GetAllCustomers(); | |
//Assert | |
Assert.NotEmpty(customers); | |
} |
And if itās a test that expects an exception I use the Assert.Throws
method:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Fact] | |
public void CustomerRepository_ThrowsException_When_NoUnitOfWorknIsFound() | |
{ | |
//Arrange | |
var repository = _container.GetRequiredService<ICustomerRepository>(); | |
var countryName = "Brazil"; | |
//Act & Assert | |
Assert.Throws<UnitOfWorkNotFoundException>(() => repository.Find_By_Country(countryName)); | |
} | |
What I don't like in the example, above is that it violates the AAA pattern. The Assert is already happening in the Act part.
While reviewing some code from one of my team members, I noticed he used the following approach to split out the Act and Assert part when using Assert.Throws
:
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
[Fact] | |
public void CustomerRepository_ThrowsException_When_NoUnitOfWorknIsFound() | |
{ | |
//Arrange | |
var repository = _container.GetRequiredService<ICustomerRepository>(); | |
var countryName = "Brazil"; | |
//Act | |
void Act() => repository.Find_By_Country(countryName); | |
//Assert | |
Assert.Throws<UnitOfWorkNotFoundException>(Act); | |
} |
He is using a Local Function to create this separation. Nice!