大量使用谓词返回数据

时间:2018-07-31 23:13:16

标签: c# moq

我正在将.Net Core 2 Web API与大量使用谓词的体系结构一起使用,这在尝试用Moq进行代码单元测试时会引起一些问题。

我的每个存储库都从具有以下基本方法的基本存储库继承:

public T GetSingle(Expression<Func<T, bool>> predicate)
{
    return _context.Set<T>().FirstOrDefault(predicate);
}

public virtual IEnumerable<T> FindBy(Expression<Func<T, bool>> predicate)
{
    return _context.Set<T>().Where(predicate);
}

在我的用户控制器注册方法中,我要确保不允许重复的电子邮件,并且这样做是这样的:

var emailCheck = _userRepository.GetSingle(x => x.Email == user.Email);
if (emailCheck != null)
{
    // duplicate
    return StatusCode(StatusCodes.Status409Conflict, "This email is already in use.");
}

在单元测试中,我想进行测试以确保我们不允许重复,所以我进行了以下设置:

public void Signup_Fail_DuplicateEmail_Controller_Test()
{
    var user = UserHelper.CreateSignupUser();
    user.Email = "duplicate@test.com";
    var uRepo = new Mock<IUserRepository>();

    uRepo.Setup(u => u.GetSingle(x => x.Email == user.Email)).Returns(user);

    var uc = new UserController(uRepo.Object);
    var result = uc.Signup(user);

    var status = Assert.IsType<StatusCodeResult>(result);
    Assert.Equal(StatusCodes.Status409Conflict, status.StatusCode);
}

无论我做什么,Setup方法始终返回null。现在,我已经在多个地方读到Moq不能与FirstOrDefault和其他类似的辅助方法一起使用,但是由于我的体系结构过于依赖谓词,因此我不确定该怎么做。当然要避免重做我的基础存储库,但是我需要能够运行这样的测试。

有想法吗?

1 个答案:

答案 0 :(得分:5)

由于无法比较表达式,因此该模拟将始终返回null。

如果这仅仅是为了测试(孤立地)被测方法的流程,则可以将It.IsAny<Expression<Func<T, bool>>>()用作参数匹配器。

public void Signup_Fail_DuplicateEmail_Controller_Test() {
    //Arrange
    var user = UserHelper.CreateSignupUser();
    user.Email = "duplicate@test.com";
    var uRepo = new Mock<IUserRepository>();

    uRepo
        .Setup(_ => _.GetSingle(It.IsAny<Expression<Func<T, bool>>>()))
        .Returns(user);

    var uc = new UserController(uRepo.Object);

    //Act
    var result = uc.Signup(user);

    //Assert
    var status = Assert.IsType<StatusCodeResult>(result);
    Assert.Equal(StatusCodes.Status409Conflict, status.StatusCode);
}

引用Moq Quickstart

上面的方法很好地用于测试隔离单元测试中的预期行为。

但是,如果您要测试实际表达式,则可以使用内存集成测试或实际数据库来完成。