The Arrange, Act, Assert (AAA) pattern gives a unit test a readable three-part structure: prepare inputs and dependencies, invoke the method under test, then verify its behavior. section 7.4.3
Use the phases to keep setup, execution, and verification distinct:
- Arrange initializes objects, prepares input data, and configures fake dependencies, such as returning default(Customer) when no customer exists. section 7.4.3
- Act invokes the method under test with the arranged parameters, such as reading a CSV stream asynchronously. section 7.4.3
- Assert verifies expected behavior, including repository calls and the values passed to created objects. section 7.4.3
- Keep configuration and verification separate: configure a fake with Returns during Arrange, then use MustHaveHappened during Assert. section 7.4.3
Validating a CSV import
Arrange a fake customer repository to return default(Customer) for an email, Act by passing a CSV stream to ReadAsync, and Assert that GetByEmailAsync and CreateAsync were called. Match the created DTO against the expected email, name, and license. section 7.4.3
Listing 7.23 OneCustomer with validation of repository
[Fact]
public async Task ValidCustomerOneLine()
{
// Arrange
string email = "some@email.com";
string name = "A Customer";
string license = "Basic";
string csv = string.Join(',', email, name, license);
A.CallTo(() => _fakeCustomerRepo.GetByEmailAsync(email)) #1
.Returns(default(Customer)); #2
// Act
var stream = GetStreamFromString(csv);
await _csvImporter.ReadAsync(stream); #3
// Assert
A.CallTo(() =>
_fakeCustomerRepo.GetByEmailAsync(email))
.MustHaveHappened(); #4
A.CallTo(() => _fakeCustomerRepo.CreateAsync( #5
A<NewCustomerDto>.That.Matches(n => #6
n.Email == email
&& n.Name == name
&& n.License == license)))
.MustHaveHappened(); #7
}
A complete C# test demonstrates the phase comments, asynchronous Act step, configured fake, repository-call assertions, and argument matching. section 7.4.3





