ASP.NET Tests¶
WebapplicationFactory for Integration Tests with TestContainers¶
Setup containers in MyApplicationFactory.cs
public class MyApplicationFactory : WebApplicationFactory<Program>, IAsyncLifetime
{
private readonly IContainer _memGraph;
public GraphServiceApplicationFactory()
{
_memGraph = CreateMemGraphContainer();
}
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Development");
builder.ConfigureTestServices(services =>
{
// change bootstrap services here
});
}
private IContainer CreateMemGraphContainer() => new ContainerBuilder()
.WithImage("memgraph/memgraph-mage:1.18.1-memgraph-2.18.1")
.WithPortBinding(7687, 7687)
.WithPortBinding(7444, 7444)
.WithEnvironment("MEMGRAPH_USER", "admin")
.WithEnvironment("MEMGRAPH_PASSWORD", "")
.WithWaitStrategy(Wait.ForUnixContainer().UntilPortIsAvailable(7687))
.Build();
public async Task InitializeAsync()
{
await _memGraph.StartAsync();
}
Task IAsyncLifetime.DisposeAsync()
{
return _memGraph.DisposeAsync().AsTask();
}
}
Then use in Xunit class fixture
public class MyTests : IClassFixture<MyApplicationFactory>
{
private readonly MyApplicationFactory _factory;
public BootstrapTests(MyApplicationFactory factory)
{
_factory = factory;
}
[Fact]
public void Test()
{
var driver = _factory.Services.GetRequiredService<IDriver>();
using var session = driver.Session();
// etc
}
Override config sources¶
https://github.com/dotnet/aspnetcore/issues/37680#issuecomment-1235651426
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.UseEnvironment("Development");
var config = new ConfigurationBuilder()
.AddInMemoryCollection(new Dictionary<string, string?>()
{
{ $"{MemGraphConfiguration.Section}:Uri", "bolt://localhost:7687" },
{ $"{MemGraphConfiguration.Section}:Username", "admin" },
{ $"{MemGraphConfiguration.Section}:Password", "password" },
})
.Build();
builder.UseConfiguration(config);
Background Service¶
[Test]
public async Task BackgroundService_ShouldCatchAndLogErrors(){
_clientMock
.Setup(m => m.GetData())
.Throws<Exception>();
using (var cts = new CancellationTokenSource())
{
await Task.WhenAny(
_sut.StartAsync(cts.Token),
Task.Delay(1000, cts.Token));
cts.Cancel();
}
_client.Verify(m => m.GetData(), Times.AtLeast(1));
_loggerMock.Verify(
m => m.Log(
It.Is<LogLevel>(l => l == LogLevel.Error),
It.IsAny<EventId>(),
It.Is<It.IsAnyType>((obj, type) => true),
It.IsAny<Exception>(),
It.Is<Func<It.IsAnyType, Exception, string>>((obj, type) => true)
),
Times.AtLeast(1));
}
Setup Controller as SUT¶
_sut = _fixture
.Build<MyController>()
.OmitAutoProperties()
.Create();
Controller Endpoint Attributes¶
[Test]
public void MyController_UsesCorrectAttributes(){
var endpointMethod = _sut.GetType().GetMethod("SomeEndpoint");
Assert.That(endpointMethod, Has.Attribute<HttpGetAttribute>())
Assert.That(endpointMethod, Has.Attribute<RouteAttribute>().Property("Template").EqualTo("books/{id}"));
}
Controller Endpoint Response¶
// Arrange
var books = _fixture.CreateMany<BookDto>().ToList();
_bookRepoMock
.Setup(m => m.GetBooks())
.Returns(books);
// Act
var response = await _sut.MyEndpointMethod();
// Assert
_bookRepoMock.Verify(m => m.GetBooks(), Times.Once);
Assert.That(response, Is.TypeOf<OkObjectResponse>()));
var objResponse = response as OkObjectResponse;
Assert.That(objResponse?.Value, Is.Not.Null);
Assert.That(objResponse!.Value, Is.TypeOf<BookDto[]>());
var booksResult = objResult as BookDto[];
Assert.That(booksResult, Is.Not.Null.And.Not.Empty);
Assert.That(
booksResult!.Select(b => b.Title),
Is.EquivalentTo(books.Select(b => b.Title));
);