我正在尝试实施集成测试,因此我只能使用HttpClient测试端点
public async Task TestEndPoint()
{
using (var response = await _client.GetAsync($"/api/car/{id}"))
{
//...
}
}
我正在使用Fixture类来帮助我
private readonly TestServer _server;
public Fixture()
{
var dbContextOptions = new DbContextOptionsBuilder<CarDbContext>()
.UseInMemoryDatabase(Guid.NewGuid().ToString())
.Options;
var mockContext = new Mock<CarDbContext>(dbContextOptions);
var mockOwnerSet = new Mock<DbSet<Owner>>();
var mockCarSet = new Mock<DbSet<Car>>();
mockContext.Setup(m => m.Owners).Returns(mockOwnerSet.Object);
mockContext.Setup(m => m.Cars).Returns(mockCarSet.Object);
var carService = new CarService(mockContext.Object);
_server = new TestServer(new WebHostBuilder()
.ConfigureAppConfiguration((context, conf) =>
{
conf.AddJsonFile(@Directory.GetCurrentDirectory() + "../appsettings.json");
}).UseStartup<Startup>()
.ConfigureServices(services =>
{
services.AddDbContext<CarDbContext>(options => options.UseInMemoryDatabase("Test"));
services.AddScoped<ICarService>(_ => carService);
})
);
Client = _server.CreateClient();
}
内部Startup.cs
public class Startup
{
public void ConfigureServices(IServiceCollection services)
{
services.AddDbContext<CarDbContext>(options => { options.UseSqlServer(Configuration.GetConnectionString("Db")); });
services.AddTransient<ICarService, CarService>();
}
}
服务类
public class CarService: ICarService {
private readonly CarDbContext _carDbContext;
public CarService(CarDbContext carDbContext)
{
_carDbContext = carDbContext;
}
public async Task<Car> GetAsync(int id)
{
return await _carDbContext.Cars.FindAsync(id); //this always returns null
}
}
我的问题是: 为什么在CarService内未使用模拟数据库上下文
返回等待状态_carDbContext.Cars.FindAsync(id); 总是返回null
更新:
private readonly TestServer _server;
public TestServer Server;
public Fixture()
{
_server = new TestServer(new WebHostBuilder()
.ConfigureAppConfiguration((context, conf) =>
{
conf.AddJsonFile(@Directory.GetCurrentDirectory() + "../appsettings.json");
}).UseStartup<Startup>()
.ConfigureServices(services =>
{
services.AddDbContext<CarDbContext>(options => options.UseInMemoryDatabase(Guid.NewGuid().ToString()));
})
);
Client = _server.CreateClient();
Server = _server;
}
//内部测试方法
using (var scope = _server.Host.Services.CreateScope())
{
var db = scope.ServiceProvider.GetRequiredService<CarDbContext>();
db.Database.EnsureDeleted();
Utilities.Seed(db);
}
和种子数据
public static class Utilities
{
public static void Seed(CarDbContext db)
{
db.Cars.Add(new Car("1", "White", "Toyota"));
db.SaveChanges(true);
}
}
我到底在哪里做错了什么? 在
中检索数据时,我仍为nullpublic async Task<Car> GetAsync(int id)
{
return await _carDbContext.Cars.FindAsync(id); //this always returns null
}
答案 0 :(得分:3)
您不需要模拟上下文或服务。删除_server = new TestServer
行之前的所有内容。在Web主机设置中,您已经设置了上下文以使用内存中的提供程序,因此这是必需的。上下文将被注入到服务中,并且服务将被注入到需要的地方。这里唯一改变的是上下文连接。它不会像SQL Server实例那样直接运行,而只是存储和从内存中检索。
测试所要做的唯一另一件事就是将要测试的数据作为“数据库”的种子。在测试中,您需要访问测试服务器实例并执行以下操作:
using (var scope = _server.Host.Services.CreateScope())
{
var context = scope.ServiceProvider.GetRequiredService<CarDbContext>();
context.EnsureDeleted();
// seed test data
}
// test code