验证Moq中的自定义对象作为参数

时间:2018-04-17 03:29:02

标签: c# moq

我对Moq测试框架相当新,我目前正在尝试创建一个将对象作为其参数之一的模拟方法。但是,我想验证它传递的对象是否具有为我继续设置的正确属性。

我有类似的东西:

private ICustomClient GetMockClient()
{
    var client = new Mock<ICustomClient>();

    var query = new CustomQueryModel
    {
        Alias = "alias:12345",
        Type = QueryTypes.Alias
    }

    client
        .Setup(client => client.GetAccountByAlias(
            new[] {It.Is<CustomQueryModel>(p => p.Alias == query.Alias && p.Type == query.Type
        )}, CancellationToken.None))
        .ReturnsAsync(new ResultModel()
        {
            results = new List<ResultModel>()
            { ... }
        });

    return client.Object
}

当我按以下方式进行比较时,我收到:

  

不支持的表达式:new [] {Is(p =&gt;((p.Alias == value(

对于更多上下文,GetAccountByAlias方法采用以下参数:GetAccountByAlias(IEnumberable<CustomQueryModel> query, CancellationToken cancellationToken)

我如何使用Moq或其他C#技术验证正确的对象,在这种情况下,query是传递给方法的对象。

由于

1 个答案:

答案 0 :(得分:1)

您的代码存在一些问题,但相当容易修复。

首先,一些管道因为我们其他人没有你的课程定义

public enum QueryTypes
{
    Alias
}

public class CustomQueryModel
{
    public string Alias
    {
        get;
        set;
    }

    public QueryTypes Type
    {
        get;
        set;
    }
}

public class ResultModel
{
}

public interface ICustomClient
{
    IEnumerable<ResultModel> GetAccountByAlias(IEnumerable<CustomQueryModel> query, CancellationToken cancellationToken);
}

public class ClassUnderTest
{
    private readonly ICustomClient client;

    public ClassUnderTest(ICustomClient client)
    {
        this.client = client;
    }

    public IEnumerable<ResultModel> MethodConsumingGetAccountByAlias(IEnumerable<CustomQueryModel> queries, CancellationToken cancellationToken)
    {
        // Do whatever your class does before / after it calls client.GetAccountByAlias
        return this.client.GetAccountByAlias(queries, cancellationToken);
    }
}

我已将您的接口查询参数重命名为查询,因为您允许多个,并且在处理作为单个实例的查询对象和具有相同名称的那些对象的列表时会非常混乱。

测试用例代码如下,但首先是一些快速注释:

我的Moq版本不支持ReturnsAsync。我将转换作为练习留给读者,因为它非常直接。

您会注意到我对Setup方法感到放松。测试用例应该做好两件事:

  1. 如果功能被破坏则失败; AND
  2. 在发生故障时提供有用的断言失败。
  3. 在编写测试用例时,太多人忘了(2)。当然,你可以在你的设置中完成所有这些,它将完美地实现(1),但是如果发生故障,你将不得不深入研究。举例来说,想象上面的MethodConsumingGetAccountByAlias并不是简单地返回来自客户端的响应,但在其上执行了.Where()表达式。如果将错误的参数传递给客户端,则模拟客户端将返回null。 null.Where()将给你一个NullReferenceException。你会弄清楚出了什么问题吗?当然,但需要一些努力。这就是为什么下面的模拟设置为始终返回正确的输出。验证方法是您确认使用所需参数调用客户端的地方。

        [Test]
        public void ShouldCallClientWithCorrectQueryObjects()
        {
            // Arrange
            Mock<ICustomClient> client = new Mock<ICustomClient>();
    
            // Permissive on the setup, return good data no matter what the input.
            client.Setup(s => s.GetAccountByAlias(It.IsAny<IEnumerable<CustomQueryModel>>(), It.IsAny<CancellationToken>()))
                  .Returns(new List<ResultModel>());
    
            CustomQueryModel query = new CustomQueryModel
                                     {
                                         Alias = "alias:12345",
                                         Type = QueryTypes.Alias
                                     };
            CancellationToken cancellationToken = new CancellationToken();
            // Act
            ClassUnderTest test = new ClassUnderTest(client.Object);
            IEnumerable<ResultModel> actualResults = test.MethodConsumingGetAccountByAlias(new[] { query }, cancellationToken);
    
            // Assert
            Func<IEnumerable<CustomQueryModel>, bool> validateModelFunc = models =>
                                                                          {
                                                                              // Test what you want to about your query parameter
                                                                              List<CustomQueryModel> results = models.ToList();
                                                                              Assert.That(results.Count, Is.EqualTo(1), "Too many elements in queries");
                                                                              Assert.That(results[0], Is.SameAs(query), "Unexpected CustomQueryModel object");
                                                                              return true;
                                                                          };
    
            // Now we can check that test called client.GetAccountByAlias with the right parameters
            client.Verify(v => v.GetAccountByAlias(It.Is<IEnumerable<CustomQueryModel>>(m => validateModelFunc(m)),
                                                   cancellationToken),
                          Times.Once());
    
            Assert.That(actualResults, Is.Not.Null); // or whatever
        }