Integrating with xUnit
If you are writing only a few Alba specifications in your testing project and your application spins up very quickly, you can just happily write tests like this:
[Fact]
public async Task should_say_hello_world()
{
// Alba will automatically manage the lifetime of the underlying host
await using var host = await AlbaHost.For<global::Program>();
// This runs an HTTP request and makes an assertion
// about the expected content of the response
await host.Scenario(_ =>
{
_.Get.Url("/");
_.ContentShouldBe("Hello World!");
_.StatusCodeShouldBeOk();
});
}
Do note that your [Fact]
method needs to be declared as async Task
to ensure that xUnit finishes the specification before disposing the system or you'll get unusual behavior. Also note that you really need to dispose the AlbaHost
to shut down your application and dispose any internal services that might be holding on to computer resources.
Class Fixtures
If your application startup time becomes a performance problem, and especially in larger test suites, you probably want to share the AlbaHost
object between tests. xUnit helpfully provides the class fixture feature for just this use case.
Build out your AlbaHost
in a class like this:
public class WebAppFixture : IAsyncLifetime
{
public IAlbaHost AlbaHost = null!;
public async Task InitializeAsync()
{
AlbaHost = await Alba.AlbaHost.For<WebApp.Program>(builder =>
{
// Configure all the things
});
}
public async Task DisposeAsync()
{
await AlbaHost.DisposeAsync();
}
}
Then in your actual xUnit fixture classes, implement the IClassFixture<T>
class like this:
public class ContractTestWithAlba : IClassFixture<WebAppFixture>
{
public ContractTestWithAlba(WebAppFixture app)
{
_host = app.AlbaHost;
}
private readonly IAlbaHost _host;
Collection Fixtures
In the previous section, the WebAppFixture
instance will only be shared between all the tests in the one ContractTestWithAlba
class. To reuse the IAlbaHost
across multiple test fixture classes, you'll need to use xUnit.Net's Collection Fixture concept.
Still using WebAppFixture
, we'll now need to have a marker collection class like this:
[CollectionDefinition("scenarios")]
public class ScenarioCollection : ICollectionFixture<WebAppFixture>
{
}
As a convenience, I like to have a base class for all test fixture classes that will be using scenarios like this:
[Collection("scenarios")]
public abstract class ScenarioContext
{
protected ScenarioContext(WebAppFixture fixture)
{
Host = fixture.AlbaHost;
}
public IAlbaHost Host { get; }
}
And then inherit from that ScenarioContext
base class in actual test fixture classes:
public class sample_integration_fixture : ScenarioContext
{
public sample_integration_fixture(WebAppFixture fixture) : base(fixture)
{
}
[Fact]
public Task happy_path()
{
return Host.Scenario(_ =>
{
_.Get.Url("/fake/okay");
_.StatusCodeShouldBeOk();
});
}
}