WebApplicationFactory for BaseTest class


There are many ways we can structure our tests. Here is a small example to get started! Using this base class, we are trying to test our system from out user's perspective.

public abstract class BaseWebApplicationFactory<TProgram> : IClassFixture<WebApplicationFactory<TProgram>> where TProgram : class
{
    protected readonly HttpClient Client;
    private readonly WebApplicationFactory<TProgram> _factory;
    private readonly SqliteConnection _connection;
    
    protected IServiceProvider ServiceProvider; // usage: var uowService = ServiceProvider.GetRequiredService<IUnitOfWork>(); var books = await uowService.BookRepository.GetAll().FirstAsync();
    
    protected BaseWebApplicationFactory(WebApplicationFactory<TProgram> factory)
    {
        _factory = factory;
        
        _connection = new SqliteConnection("DataSource=:memory:");
        _connection.Open();        Client = _factory.WithWebHostBuilder(builder =>
        {
            builder.ConfigureServices(services =>
            {
                // Remove the existing context configuration if any
                var descriptor = services.SingleOrDefault(d => d.ServiceType == typeof(DbContextOptions<ApplicationDbContext>));
                if (descriptor != null)
                    services.Remove(descriptor);                // Add ApplicationDbContext using SQLite in-memory database
                services.AddDbContext<ApplicationDbContext>(options =>
                {
                    options.UseSqlite(_connection);
                });                // Add other necessary services like IUnitOfWork, IMapper, IMediator, ICreateLinks etc.
                services.AddScoped<IUnitOfWork, UnitOfWork>();
                services.AddAutoMapper(typeof(Program));
                services.AddMediatR(m => m.RegisterServicesFromAssemblyContaining<Program>());
                
                // Add your services and repository here
                services.AddScoped<IBookRepository, BookRepository>();
                services.AddScoped<ICreateLinks, CreateLinks>();                // Ensure the database is created and migrated before running tests
                ServiceProvider = services.BuildServiceProvider();
                using var scope = ServiceProvider.CreateScope();
                var db = scope.ServiceProvider.GetRequiredService<ApplicationDbContext>();
                db.Database.EnsureCreated();
                
            });
        }).CreateClient();
    }    public void Dispose()
    {
        _connection.Close();
        // _connection.Dispose();
    }
}

The usage:

public class BooksControllerWebAppTests: BaseWebApplicationFactory<Program>
{
    public BooksControllerWebAppTests(WebApplicationFactory<Program> factory) : base(factory)
    {
    }
    
    [Fact]
    public async Task GetBooks()
    {
        // Arrange & Act
        var response = await Client.GetAsync("/books");
        
        // Assert: Check that the response status code is 200 OK
        response.EnsureSuccessStatusCode();
        var responseString = await response.Content.ReadAsStringAsync();
        
        // Optionally, deserialize response content
        var books = JsonConvert.DeserializeObject<List<Book>>(responseString);
        Assert.NotNull(books);
        Assert.NotEmpty(books);
    }
    
    [Fact]
    public async Task GetById()
    {
        // Arrange
        
        // alternative using the service
        // var uowService = ServiceProvider.GetRequiredService<IUnitOfWork>();
        // var books = await uowService.BookRepository.GetAll().FirstAsync();
        var bookInDb = DefaultData.DefaultBooks.First();
        Assert.NotNull(bookInDb);
        
        // Act
        var response = await Client.GetAsync($"/books/id/{bookInDb.Id}");
        
        // Assert: Check that the response status code is 200 OK
        response.EnsureSuccessStatusCode();
        var responseString = await response.Content.ReadAsStringAsync();
        var bookResponse = JsonConvert.DeserializeObject<Book>(responseString);
        Assert.NotNull(bookResponse);
        Assert.Equal(bookInDb.Id, bookResponse.Id);
        Assert.Equal(bookInDb.Isbn, bookResponse.Isbn);
    }
    
    [Fact]
    public async Task GetById_NotFound()
    {
        // Arrange & Act
        var response = await Client.GetAsync($"/id/{Guid.Empty}");
        
        // Assert: Check that the response status code is 404 OK
        Assert.Equal(404, (int)response.StatusCode);
    }   

       // Add more tests...
}

 


No files yet, migration hasn't completed yet!