Tutorial

2.5 Test the host

A host test starts the whole application in memory, as dotnet run would, and calls it over HTTP. It is the test that fails when Program.cs no longer starts or an endpoint answers with the wrong status.

tests/Shopfront.Tests/IntegrationTests/HostTests.cs:

using System.Net;
using System.Net.Http.Json;
using Microsoft.AspNetCore.Mvc.Testing;
using Shopfront.Trains.PlaceOrder;
 
namespace Shopfront.Tests.IntegrationTests;
 
[TestFixture]
public class HostTests
{
    private WebApplicationFactory<Program> _app = null!;
 
    [SetUp]
    public void StartTheApplication() => _app = new WebApplicationFactory<Program>();
 
    [TearDown]
    public ValueTask StopTheApplication() => _app.DisposeAsync();
 
    [Test]
    public async Task PostOrders_InStock_Answers200WithTheOrder()
    {
        var response = await _app.CreateClient()
            .PostAsJsonAsync(
                "/orders",
                new { customerId = "ada", lines = new[] { new { sku = "MUG", quantity = 2 } } }
            );
 
        response.StatusCode.Should().Be(HttpStatusCode.OK);
        var order = await response.Content.ReadFromJsonAsync<PlaceOrderOutput>();
        order!.Total.Should().Be(24.00m);
    }
 
    [Test]
    public async Task PostOrders_OutOfStock_Answers422WithTheReason()
    {
        var response = await _app.CreateClient()
            .PostAsJsonAsync(
                "/orders",
                new { customerId = "ada", lines = new[] { new { sku = "CAP", quantity = 1 } } }
            );
 
        response.StatusCode.Should().Be(HttpStatusCode.UnprocessableEntity);
        (await response.Content.ReadFromJsonAsync<string>()).Should().Be("CAP is out of stock.");
    }
}

WebApplicationFactory<Program> runs Program.cs with a test server in place of Kestrel. The InternalsVisibleTo line is what lets the tests name Program at all.

The requests are anonymous objects rather than PlaceOrderInput, on purpose: they send the JSON a real client sends, so a renamed property shows up here as a failing test instead of passing on both sides.

SDK Reference

ITrainBus | UseInMemory | SaveTrainParameters | Metadata | Mediator testing | Architecture guards


Next: 2.6 Guard the project's shape