我正在尝试对Blazor项目的服务器API进行单元测试
因此,我有这个构造器为我的API接收工厂
public MyThingApi(IDbContextFactory<MyDbContext> factory)
{
this.factory = factory;
}
然后我有这个功能来获得我的东西列表:
public async Task<List<MyThing>> GetMyThingsAsync()
{
using var context = factory.CreateDbContext();
return await context.MyThings.ToListAsync();
}
现在,如果我想使用Moq测试GetMyThingsAsync,我必须模拟工厂。但模拟代码看起来像:
Mock<IDbContextFactory<MyDbContext>>
这就是我不明白的:MyDbContext不是一个接口。因此,在代码中CreateDbContext将始终返回一个MyDbContext。所以我不能嘲笑它,它将是";真实的";上下文中有一个";真实的";数据库连接。上下文也是如此。MyThings将从数据库中检索它。
那么,当上下文由工厂生成时,模拟上下文的魔力是什么呢?
这个答案使用内存数据库,这使得整个模拟非常简单。
步骤1:
在单元测试项目中安装这些nuget包:
- Microsoft.EntityFrameworkCore.IMemory
- Moq
- xunit
- Shouldly
步骤2:
这样设置测试:
using Moq;
using Shouldly;
using Microsoft.EntityFrameworkCore;
namespace YourProject.UnitTests;
public class YourTests
{
[Fact]
public async Task Should_Get_My_ThingsAsync()
{
// ARRANGE
var mockDbFactory = new Mock<IDbContextFactory<MyDbContext>>();
var options = new DbContextOptionsBuilder<MyDbContext>()
.UseInMemoryDatabase(databaseName: "SomeDatabaseInMemory")
.Options;
// Insert seed data into the database using an instance of the context
using (var context = new MyDbContext(options))
{
context.MyThings.Add(new MyThing { Id = 1, SomeProp = "Some Prop Value" });
context.MyThings.Add(new MyThing { Id = 2, SomeProp = "Some Prop Value" });
context.SaveChanges();
}
// Now the in-memory db already has data, we don't have to seed everytime the factory returns the new DbContext:
mockDbFactory.Setup(f => f.CreateDbContextAsync(It.IsAny<CancellationToken>())).ReturnsAsync(() => new MyDbContext(options));
// ACT
var myThingApi = new MyThingApi(mockDbFactory.Object);
var result = await myThingApi.GetMyThingsAsync();
// ASSERT
result.ShouldNotBeNull();
result.Count.ShouldBe(2);
// other asserts
}
}
我使用内存中的sqlite数据库进行测试。