繁体   English   中英

System.NotSupportedException:不支持的表达式:x => x

[英]System.NotSupportedException : Unsupported expression: x => x

我目前正在尝试最小化我的Cafe Get方法,如果找不到咖啡馆 ID,该方法将抛出ArgumentNullexception

错误

System.NotSupportedException: Unsupported expression: x => x.Cafe Non-overridable members (here: Context.get_Cafe) may not be used in setup / verification expressions.

发生这种情况是因为最小起订量无法处理其中一个设置表达式吗?

单元测试

[Fact]
public async Task GetCafeByIdAsync_Should_Throw_ArgumentNullException()
{
    var cafe = new List<Cafe>()
    {
        new Cafe { Name = "Hanna", CafeId = 1},
        new Cafe { Name = "Bella", CafeId = 2 }
    }.AsQueryable();

    var mockSet = new Mock<DbSet<Cafe>>();
    mockSet.As<IQueryable<Cafe>>().Setup(m => m.Provider).Returns(cafe.Provider);
    mockSet.As<IQueryable<Cafe>>().Setup(m => m.Expression).Returns(cafe.Expression);
    mockSet.As<IQueryable<Cafe>>().Setup(m => m.ElementType).Returns(cafe.ElementType);
    mockSet.As<IQueryable<Cafe>>().Setup(m => m.GetEnumerator()).Returns(cafe.GetEnumerator());

    var mapper = new MapperConfiguration(cfg =>
    {
        cfg.AddProfile(new AutoMapperProfile());
    }).CreateMapper();

    var contextMock = new Mock<Context>();
    contextMock.Setup(x => x.Cafe).Returns(mockSet.Object); //failing here

    var cafeService = new CafeService(contextMock.Object, mapper);

    await Assert.ThrowsAsync<ArgumentNullException>(() => cafeService.Get(2));
}

被测系统

public async Task<VersionResponse> Get(int cafeId)
{
    var cafe = await _context.Cafe.Where(w => w.CafeId == cafeId).ToResponse().FirstOrDefaultAsync();
    return new VersionResponse()
    {
        Data = cafe
    };
}

Moq 依赖于能够创建覆盖属性的代理类。 Context.Cafe不能被覆盖。 尝试将该属性声明为virtual

public virtual IDbSet<Cafe> Cafe { get; set; }

尝试在Set方法上设置模拟

public virtual DbSet<TEntity> Set<TEntity>() where TEntity : class;

在你的情况下

var contextMock = new Mock<Context>();
contextMock.Setup(x => x.Set<Cafe>()).Returns(mockSet.Object);

我有一个更好的集成测试方法 你可以使用事务回滚来进行这种类型的测试,这样你就可以在 Db 中做任何你想做的事,然后 Db 中的每一个动作都回到运行测试之前的最后一个 state

如果你使用 Ef,你可以将这个 class 添加到你的测试项目中并享受它

public abstract class PersistTest<T> : IDisposable where T : DbContext, new()
{
    protected T DBContext;
    private TransactionScope scope;
    protected PersistTest()
    {
        scope = new TransactionScope();
        DBContext = new T();
    }

    public void Dispose()
    {
        scope.Dispose();
        DBContext.Dispose();
    }
}

这个 class 帮助你编写更好的集成测试,

你的测试 class 应该继承自这个抽象 class 并将你的上下文 class 作为 DbContext 的实例传递

关于您的 Codd 的另一件事是您应该将 Logic 和 DataAccess 彼此分开

只需定义一个名为 ICofeeRepository 的接口并在其中采用您的方法您的代码打破单一责任原则

你的服务应该是这样的

public class CoffeService
{
    //inject cafe repository ; _repo
    public async Task<VersionResponse> Get(int cafeid)
    {
        var cafe = _repo.FindById(cafeid);
        if (cafe == null)
            throw Exception("");
        //other wise .....
    }
}

你的存储库应该是这样的

public interface ICafeRepository
{
    Cafe Get(int cafeid);
}

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM