.NET Core / Web API71 min total · 19 parts
Building REST APIs with ASP.NET Core: Routing, Middleware, and Dependency Injection
Part 18 of 19 · ~1 min
Testing Web API Controllers
DI being the thing that wires up practically everything in ASP.NET Core has a pleasant side effect: ReservationsController was testable on its own from the very first version — build it directly, hand it a mock, and there's no web server anywhere in the picture:
[Fact]
public async Task Create_ReturnsConflict_WhenSlotAlreadyBooked()
{
var mockService = new Mock<IReservationService>();
mockService.Setup(s => s.CreateAsync(1, It.IsAny<CreateReservationRequest>()))
.ReturnsAsync(new ReservationResult { Conflict = true });
var controller = new ReservationsController(mockService.Object);
var result = await controller.Create(1, new CreateReservationRequest { StartUtc = DateTime.UtcNow, DurationMinutes = 15 });
Assert.IsType<ConflictObjectResult>(result.Result);
}
"Keep the controller thin, push logic into an injected service" pays off precisely here, beyond just tidiness. ReservationsController.Create only ever talks to IReservationService, so a mock is the entire test fixture — nothing touching a real database anywhere along the way. Put the same logic straight into the controller, reading and writing BenchDbContext inline, and this style of test stops being possible; proving even one branch works now means standing up something far heavier.
That heavier tool has its place too, and Bench's own incident is exactly the case for it: WebApplicationFactory<TEntryPoint> boots the real app, in process, with its actual DI registrations and its actual middleware pipeline, and lets a test fire genuine HTTP requests at it rather than calling a method directly. The regression test Dana wrote after the postmortem sends two concurrent POSTs at the identical slot through that real, fully-wired app and checks that exactly one comes back 201 while the other comes back 409. Had that test existed a month earlier, attempt three from the lifetimes chapter would never have reached a single kiosk.