【问题标题】:Setup method with FindOptions<T> as parameter in UnitTest using Moq使用 Moq 在 UnitTest 中使用 FindOptions<T> 作为参数的设置方法
【发布时间】:2018-01-22 19:25:55
【问题描述】:

想象一下我有这门课:

public class MyClass
{
    public string Id { get; set; }
    public string Name { get; set; }
    public IList<MyOtherClass> MyOtherClassList { get; set; }
}

我想用Moqxunit 对我的服务层进行单元测试:

public IList<MyClass> GetAll()
{
    var options = new FindOptions<MyClass>
    {
        Projection = Builders<MyClass>.Projection
            .Exclude(m => m.MyOtherClassList)
    };

    return MyClassRepository.GetAll(options)
}

这将是测试:

[Fact]
public void GetAll_Success()
{
    //Arrange
    List<MyClass> expected = ... ;

    var mockMyClassRepository = new Mock<IMyClassRepository>();
    mockMyClassRepository.Setup(m => m.GetAll(It.IsAny<FindOptions<MyClass>>())).Returns(expected); 

    var myClassService = new MyClassService(mockMyClassRepository);

    //Act
    var result = myClassService.GetAll();

    //Assert
    Assert.Equal(expected, result);
    mockMyClassRepository.Verify(m => m.GetAll(It.IsAny<FindOptions<MyClass>>()), Times.Once);
}

我想避免对 FindOptions 使用 It.IsAny 并确保 findOptions 不包括 MyOtherClassList 属性,但我不确定如何比较 FindOptions 类。

有什么建议吗?

【问题讨论】:

  • 您是否真的要使用模拟而不是测试数据库对 DAL 进行单元测试?
  • @DannyVarod 这是一种非常常见的方法,仅供参考
  • 好吧,我正在采用这种方法,但如果您可以分享任何文章以提供有关为什么使用测试数据库更好的更多信息,那将非常有帮助。
  • 实际上我在这里测试的是服务层,而不是 DAL。
  • @DannyVarod 我没说这是个好方法;)

标签: c# unit-testing moq mongodb-.net-driver


【解决方案1】:

这是怎么回事

mockMyClassRepository
.Setup(m => m.GetAll(It.IsAny<FindOptions<MyClass>>()))
.Returns(FindOptions<MyClass> a) =>
{
    if (a.MyOtherClass != null || a.MyOtherClass.Length() > 0)
       throw new InvalidOperationException();
    else
       return expected;
});

【讨论】:

    【解决方案2】:

    您可以在 Returns 中使用表达式来检查提供的参数,以便应用您想要的任何过滤。

    mockMyClassRepository
        .Setup(_ => _.GetAll(It.IsAny<FindOptions<MyClass>>()))
        .Returns((FindOptions<MyClass> options) => {
            var projection = options.Projection;
            //...use as desired to filter the expected.
            return expected;
        }); 
    

    同样可以在Callback 中完成,其中expected 可以再次根据传递的参数进行操作/更改。

    请注意,对传递的参数所做的事情是一个实现问题,适用于您尝试模拟的实际存储库所做的事情。

    确保findOptions 实际上排除MyOtherClassList 属性的唯一方法是通过集成测试。

    【讨论】:

      【解决方案3】:

      如果您希望更具体地了解 .Verify 调用,可以将 .Setup 调用保留为使用 It.IsAny,然后在验证调用中使用其他约束,如下所示:

      mockMyClassRepository.Verify(m => m.GetAll(It.Is<FindOptions<MyClass>>(options => 
                                options.Projection == .... //whatever logic would return true for your success criteria
                                  )), Times.Once);
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-10-04
        • 2020-08-02
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-07-24
        • 1970-01-01
        • 2016-03-15
        相关资源
        最近更新 更多