The test stack and its idioms
Four libraries, and you’ll recognise the shape from Jest even though the names differ. xUnit is the runner: [Fact] marks a test method (like it(...)). Shouldly is the assertion library: result.IsSuccess.ShouldBeTrue(), value.ShouldBe(60), Should.Throw<T>(...), readable and specific. NSubstitute is the mock library: Substitute.For<IRepo>() fakes an interface. AutoFixture builds test data so you don’t hand-construct objects whose exact values don’t matter.
public class FlightNumberVoTests
{
public class Create
{
[Fact]
public void ValidValue_ReturnsSuccess()
{
var result = FlightNumberVo.Create("4088");
result.IsSuccess.ShouldBeTrue();
result.Value.Value.ShouldBe("4088");
}
[Fact]
public void NullValue_ReturnsFailure()
{
var result = FlightNumberVo.Create(null);
result.IsFailure.ShouldBeTrue();
result.Errors.ShouldContain(e => e.Field == "Value" && e.Message.Contains("required"));
}
}
}var repo = Substitute.For<IFlightDisruptionAggregateRepository>();
repo.LoadRevertSummary(TestFlightKey).Returns(
new FlightRevertSummary(42, "4088", TestFlightKey, HasActiveDecision: true));
var useCase = new RevertDisruptionDecision(repo, () => FixedNow); // fixed clock
var result = await useCase.Execute(new RevertDisruptionDecisionRequest(TestFlightKey));
result.IsSuccess.ShouldBeTrue();
await repo.Received(1).MarkAsReverted(42, TestFlightKey, FixedNow); // verify the interactionTry it yourself
Test the VO you built
Write the test the way the team writes it, boundaries included.
- For the
BookingReferenceVofrom Module 8, write aBookingReferenceVoTestsclass with a nestedCreateclass - Add
[Fact]tests: valid 6-char reference returns success, null returns failure, a 5-char (boundary miss) returns failure - Use Shouldly:
result.IsSuccess.ShouldBeTrue(),result.Errors.ShouldContain(...) - Run
dotnet testand confirm green
How to fake a repository
Your use-case test needs a fake IFlightDisruptionAggregateRepository. What do you write?
Show answer
Correct answer: B — Substitute.For<IFlightDisruptionAggregateRepository>() and set up the methods you need with .Returns(...)
Anti-pattern #11: use NSubstitute (Substitute.For<I>()), which generates the fake from the interface so it can never drift from the contract. Hand-rolled stubs are extra maintenance the moment the interface changes.