I am setting up integration tests for my Asp.Net Core API, using xunit. So far, I have two tests setup:
public class BasicTests : IClassFixture<CustomWebApplicationFactory<EcommerceWebAPI.Startup>>
{
private readonly CustomWebApplicationFactory<EcommerceWebAPI.Startup> _factory;
public BasicTests(CustomWebApplicationFactory<EcommerceWebAPI.Startup> factory)
{
_factory = factory;
}
[Theory]
[InlineData("84.247.85.224")]
public async Task AuthenticateUserTest(string ip)
{
// Arrange
var client = _factory.CreateClient();
int responseStatusCode = 0;
// Act
var request = new HttpRequestMessage(HttpMethod.Post, "/api/Users/AuthenticateUser")
{
Content = new StringContent("{\"Username\":\"test@test.com\",\"Password\":\"test\"}", Encoding.UTF8,
"application/json")
};
request.Headers.Add("X-Real-IP", ip);
var response = await client.SendAsync(request);
responseStatusCode = (int)response.StatusCode;
// Assert
Assert.Equal(200, responseStatusCode);
}
[Theory]
[InlineData("84.247.85.224")]
[InlineData("84.247.85.225")]
[InlineData("84.247.85.226:6555")]
[InlineData("205.156.136.211, 192.168.29.47:54610")]
public async Task SpecificIpRule(string ip)
{
// Arrange
var client = _factory.CreateClient();
int responseStatusCode = 0;
// Act
for (int i = 0; i < 4; i++)
{
var request = new HttpRequestMessage(HttpMethod.Post, "/api/Users/AuthenticateUser")
{
Content = new StringContent("{\"Username\":\"Test\",\"Password\":\"Test\"}", Encoding.UTF8,
"application/json")
};
request.Headers.Add("X-Real-IP", ip);
var response = await client.SendAsync(request);
responseStatusCode = (int)response.StatusCode;
}
// Assert
Assert.Equal(429, responseStatusCode);
}
}
My custom application factory:
public class CustomWebApplicationFactory<TStartup> : WebApplicationFactory<TStartup> where TStartup : class
{
protected override void ConfigureWebHost(IWebHostBuilder builder)
{
builder.ConfigureServices(services =>
{
var descriptor = services.SingleOrDefault(
d => d.ServiceType ==
typeof(DbContextOptions<EntityContext>));
services.Remove(descriptor);
services.AddDbContext<EntityContext>(options =>
{
options.UseInMemoryDatabase("InMemoryDbForTesting");
});
var sp = services.BuildServiceProvider();
using (var scope = sp.CreateScope())
{
var scopedServices = scope.ServiceProvider;
var db = scopedServices.GetRequiredService<EntityContext>();
var logger = scopedServices
.GetRequiredService<ILogger<CustomWebApplicationFactory<TStartup>>>();
db.Database.EnsureDeleted();
db.Database.EnsureCreated();
try
{
Utilities.InitializeDbForTests(db);
}
catch (Exception ex)
{
logger.LogError(ex, "An error occurred seeding the " +
"database with test messages. Error: {Message}", ex.Message);
}
}
});
}
}
I seed the database with:
static class Utilities
{
public static void InitializeDbForTests(EntityContext db)
{
var customer = new Customer
{
Custnmbr = "AARONFIT0001"
};
db.Customers.Add(customer);
var user = new User
{
Id = 1,
Customer = customer,
EmailAddress = "test@test.com",
PasswordHash = BCrypt.Net.BCrypt.HashPassword("test")
};
db.Users.Add(user);
db.SaveChanges();
}
}
Both test cases pass. But, I get an entity already exists exception in the log when the second test tries to run the seed again. I thought putting the line db.Database.EnsureDeleted()
in my CustomWebApplicationFactory
would ensure each test starts with a brand new InMemory Database. How do I ensure a new InMemory seeded Database for each test?