简体   繁体   English

使用Moq验证List <>类型的参数?

[英]Using Moq to verify a parameter of type List<>?

Using Moq, I'd like to be able to verify that certain conditions are met on a parameter being passed to a mocked method call. 使用Moq,我希望能够验证传递给模拟方法调用的参数是否满足某些条件。 In this scenario, I'd like to check that the list passed into the mocked method is of a certain size: 在这种情况下,我想检查传递给mocked方法的列表是否具有一定的大小:

var mockSomeRepository = new Mock<SomeRepository>();
mockSomeRepository.Setup(m => m.Write(It.IsAny<List<SomeDTO>>())).Verifiable();

var mainClass = new MainClass(mockSomeRepository.Object);
List<SomeDTO> someList = GetListWith25Items();

mainClass.DoRepositoryWrite(someList); // calls SomeRepository.Write(someList);

mockSomeRepository.Verify(m => 
    m.Write(It.Is<List<SomeDTO>>(l => l.Count() == 25)), Times.Once());

The verify assert throws an exception that says the method is never called in this fashion. 验证断言抛出一个异常,表示永远不会以这种方式调用该方法。 However, removing the constraint and using Is.Any<List<SomeDTO>>() instead leads to a pass. 但是,删除约束并使用Is.Any<List<SomeDTO>>()会导致传递。 I'm not sure if I'm using It.Is<>() properly here - this is what I intuitively want my test to look like but I'm not sure if I'm using the framework properly. 我不确定我是否在这里使用It.Is <>() - 这是我直觉地希望我的测试看起来像但我不确定我是否正确使用框架。 How should I properly frame this test? 我应该如何正确地构建这个测试?

You can get rid of the call to Setup and Verifiable on your mock. 您可以在模拟上删除对SetupVerifiable的调用。 Just use Verify . 只需使用验证

I created a little test-project, and this worked for me: 我创建了一个小测试项目,这对我有用:

using System;
using System.Collections.Generic;
using System.Linq;
using Moq;

namespace csharp
{
    public class SomeDTO { }

    public class SomeRepository { public virtual void Write(List<SomeDTO> list) { } }

    public class MainClass
    {
        private SomeRepository someRepository;

        public MainClass(SomeRepository someRepository) { this.someRepository = someRepository; }

        public void DoRepositoryWrite(List<SomeDTO> list) { this.someRepository.Write(list); }
    }

    class Program
    {
        static void Main(string[] args)
        {
            var mockSomeRepository = new Mock<SomeRepository>();
            var someList = Enumerable.Repeat(new SomeDTO(), 25).ToList();

            var mainClass = new MainClass(mockSomeRepository.Object);
            mainClass.DoRepositoryWrite(someList);

            mockSomeRepository.Verify(m => m.Write(It.IsAny<List<SomeDTO>>()), Times.Once(), "Write was not called");
            mockSomeRepository.Verify(m => m.Write(It.Is<List<SomeDTO>>(l => l.Count == 25)), Times.Once(), "Write was not called with a 25-element-list");
        }
    }
}

When I posted this question, I was missing a few important details. 当我发布这个问题时,我错过了一些重要的细节。 I want to elaborate on what was actually happening in case it will help someone in the future. 我想详细说明实际发生的事情,以防将来帮助某人。 My method under test was actually clearing the list that was being passed to the mock: 我正在测试的方法实际上正在清除传递给mock的列表:

public class SomeDTO { }

public class SomeRepository
{
    public virtual void Write(IEnumerable<SomeDTO> list) { }
}

public class MainClass
{
    private readonly SomeRepository _someRepository;
    private readonly List<SomeDTO> _testList = new List<SomeDTO>(); 

    public MainClass(SomeRepository someRepository)
    {
        _someRepository = someRepository;
    }

    public void DoRepositoryWrite()
    {
        _testList.AddRange(Enumerable.Repeat(new SomeDTO(), 25));
        _someRepository.Write(_testList);
        _testList.Clear();
    }
}

class Program
{
    static void Main(string[] args)
    {
        var mockSomeRepository = new Mock<SomeRepository>();

        var mainClass = new MainClass(mockSomeRepository.Object);

        mainClass.DoRepositoryWrite();

        mockSomeRepository.Verify(m => m.Write(It.IsAny<IEnumerable<SomeDTO>>()), Times.Once(), "Write was not called");
        mockSomeRepository.Verify(m => m.Write(It.Is<IEnumerable<SomeDTO>>(l => l.Count() == 25)), Times.Once(), "Write was not called with a 25-element-list");
    }
}

Looking back it seems a little obvious, but the takeaway here for me is that the mock hangs on to a reference to the list it was passed. 回顾它似乎有点显而易见,但对我来说这里的内容是模拟挂起对它传递的列表的引用。 Therefore you need to be careful with any side effects that alter that list. 因此,您需要小心改变该列表的任何副作用。

To write the test properly, I needed to inspect the properties of the passed list immediately when the mocked method was called. 要正确编写测试,我需要在调用模拟方法时立即检查传递列表的属性。 To do this I used a callback: 为此,我使用了一个回调:

int listCountAtTimeOfCall = 0;
mockSomeRepository.Setup(
    m => m.Write(It.IsAny<IEnumerable<SomeDTO>>())).Callback
        <IEnumerable<SomeDTO>>(list => listCountAtTimeOfCall = list.Count());

... do the work ...

Assert.AreEqual(listCountAtTimeOfCall, 25);

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

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