【发布时间】:2021-10-25 12:13:42
【问题描述】:
我正在尝试构建一个能够模拟 DbContext 和服务的测试项目。
我的 DbContext:
public class ProjectDbContext : DbContext
{
public DbSet<Item> Items { get; set; }
public ProjectDbContext(DbContextOptions<ProjectDbContext> opt) : base(opt)
{}
}
可序列化:
public interface ISerializable
{
Task<bool> SaveChangesAsync();
bool SaveChanges();
}
基础服务:
public class BaseService : ISerializable
{
protected readonly ProjectDbContext context;
public BaseService(ProjectDbContext context)
{
context = context;
}
public async Task<bool> SaveChangesAsync()
{
var result = await context.SaveChangesAsync();
return result >= 0;
}
public bool SaveChanges()
{
var result = context.SaveChanges();
return result >= 0;
}
}
我的物品服务界面:
public interface IItemsService : ISerializable
{
Item GetById(Guid id);
}
物品服务:
public class ItemsService : BaseService, IItemsService
{
public ItemsService(ProjectDbContext context)
: base(context)
{ }
public Item GetById(Guid id)
{
return context.Items.FirstOrDefault(x => x.Id == id);
}
}
我的测试:
public class ItemTest
{
private readonly Mock<DbSet<Item>> _mockSet = new Mock<DbSet<Item>>();
private Mock<ProjectDbContext> _mockContext;
public ItemTest()
{
_mockContext = new Mock<ProjectDbContext >();
_mockContext.Setup(m => m.Items).Returns(_mockSet.Object);
}
[Fact]
public void GetById_ShouldReturnItemWhenItemExists()
{
// Service
var repository = new ItemsService(_mockContext.Object);
// Arrange
var itemId = Guid.NewGuid();
// Act
var item = repository.GetById(itemId, CancellationToken.None);
// Assert
Assert.Equal(itemId, item.Id);
}
}
错误信息:
System.NotSupportedException 不支持的表达式:m => m.Items 不可覆盖的成员(此处:ProjectDbContext.get_Items)不得用于设置/验证表达式。 在 C:\projects\moq4\src\Moq\Guard.cs:line 99 中的 Moq.Guard.IsOverridable(MethodInfo 方法,表达式表达式) 在 C:\projects\moq4\src\Moq\InvocationShape.cs: 84 中的 Moq.InvocationShape..ctor(LambdaExpression 表达式,MethodInfo 方法,IReadOnlyList'1 参数,布尔精确通用类型参数,布尔skipMatcherInitialization,布尔allowNonOverridable) 在 Moq.ExpressionExtensions.g__Split|5_0(表达式 e、Expression& r、InvocationShape& p、布尔赋值、布尔 allowNonOverridableLastProperty)在 C:\projects\moq4\src\Moq\ExpressionExtensions.cs:324 行 在 C:\projects\moq4\src\Moq\ExpressionExtensions.cs:line 149 中的 Moq.ExpressionExtensions.Split(LambdaExpression 表达式,布尔 allowNonOverridableLastProperty) 在 C:\projects\moq4\src\Moq\Mock.cs:line 601 中的 Moq.Mock.SetupRecursive[TSetup](Mock mock, LambdaExpression 表达式, Func'4 setupLast, Boolean allowNonOverridableLastProperty) 在 C:\projects\moq4\src\Moq\Mock.cs:line 505 中的 Moq.Mock.Setup(Mock mock, LambdaExpression 表达式, Condition 条件) 在 C:\projects\moq4\src\Moq\Mock`1.cs:line 454 中的 Moq.Mock'1.Setup[TResult](Expression'1 表达式) 在 ....\ItemTest.cs:line 20 中的 ItemTest.ctor() 处
错误显示以下行不可覆盖:
_mockContext.Setup(m => m.Items).Returns(_mockSet.Object);
我尝试将 Items DbSet 设为 virtual 成员。然后我开始得到:
Castle.DynamicProxy.InvalidProxyConstructorArgumentsException 无法实例化类的代理:....ProjectDbContext。
添加无参数构造函数会引发另一个异常,这让我觉得我做错了什么。对于我的问题,我将不胜感激。
【问题讨论】:
-
有几个专门构建的库,例如:EntityFrameworkCore3Mock、EntityFrameworkCore.Testing。你考虑过使用它们吗?
-
我尝试了第一个,对于带有 Moq 集成的 .Net5,同样的问题
-
EntityFrameworkCoreMock 支持 EFCore 5,而不是
EntityFrameworkCore3Mock。你试过哪一个? -
我尝试了适用于 EFCore 5 的那个
标签: c# unit-testing .net-core moq xunit