使用moq验证列表

时间:2011-01-19 00:28:08

标签: c# .net unit-testing mocking moq

给定调用代码

List<Person> loginStaff = new List<Person>(); 

loginStaff.add(new Person{FirstName = "John", LastName = "Doe"});

this._iViewLoginPanel.Staff = loginStaff;

验证是否存在名为john doe的员工并且至少有一名员工被设置的语法是什么?目前,我见过的所有示例都非常基本,仅使用It.IsAny或Staff =某些基本类型,但实际上没有一个验证复杂类型(如列表)中的数据。

我的断言看起来像

this._mockViewLoginPanel.VerifySet(x=> x.Staff = It.IsAny<List<Person>>());

仅检查给定位器的类型,但不检查列表本身的大小或项目。我试过这样的事情:

        this._mockViewLoginPanel.VerifySet(
           x =>
           {
               List<string> expectedStaffs = new List<string>{"John Doe", "Joe Blow", "A A", "Blah"};
               foreach (Person staff in x.Staff)
               {
                   if (!expectedStaffs.Contains(staff.FirstName + " " + staff.LastName))
                       return false;
               }
               return true;
           });

但是这告诉我lambda语句体不能转换为表达式树。 然后我得到了将语句体放入函数并运行它的想法,但在运行时我得到:

  

System.ArgumentException:Expression不是属性setter调用。

更新 根据使用assert的前两个答案,我尝试了该方法,但发现即使将Staff设置为非空列表,它仍然在调试中显示为null。所以这就是完整测试的样子

[TestMethod]
public void When_The_Presenter_Is_Created_Then_All_CP_Staff_Is_Added_To_Dropdown()
{
    this._mockViewLoginPanel = new Mock<IViewLoginPanel>();

    PresenterLoginPanel target = new PresenterLoginPanel(this._mockViewLoginPanel.Object);

    this._mockViewLoginPanel
        .VerifySet(x => x.Staff = It.IsAny<List<Person>>());

    Assert.AreEqual(5, this._mockViewLoginPanel.Object.Staff.Count);
}

在PresenterLoginPanel

的构造函数中的某个位置
public PresenterLoginPanel
{
    private IViewLoginPanel _iViewLoginPanel;

    public PresenterLoginPanel(IViewLoginPanel panel) 
    { 
        this._iViewLoginPanel = panel;
        SomeFunction();
    }

    SomeFunction() {
        List<Person> loginStaff = new List<Person>(); 

        loginStaff.add(new Person{FirstName = "John", LastName = "Doe"});

        this._iViewLoginPanel.Staff = loginStaff;
    }
}

当我调试到下一行时,this._iViewLoginPanel.Staff为空,这是导致断言中出现空异常的原因。

3 个答案:

答案 0 :(得分:14)

您可以使用NUnit方法对模拟对象的内容进行断言,而不是使用mock的方法。

一旦您将列表分配给对象并验证它已设置,请使用断言检查细节,例如项目计数以及第一个对象与您期望它包含的内容相匹配。

Assert.That(this._mockViewLoginPanel.Object.Staff.Length, Is.EqualTo(1));
Assert.That(this._mockViewLoginPanel.Object.Staff[0], Is.Not.Null);
Assert.That(this._mockViewLoginPanel.Object.Staff[0], Is.EqualTo(loginStaff[0]));

修改

经过进一步调查后,这归结为模拟行为。未正确设置属性StaffPerson

设置它们,将模拟创建改为:

var _mockViewLoginPanel = new Mock<IViewLoginPanel>(MockBehavior.Strict);
_mockViewLoginPanel.SetupAllProperties();

演示的完整代码清单是:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }
}

public interface IViewLoginPanel
{
    IList<Person> Staff { get; set; }
}

public class PresenterLoginPanel {

    private IViewLoginPanel _iViewLoginPanel;

    public PresenterLoginPanel(IViewLoginPanel panel) 
    { 
        _iViewLoginPanel = panel;
        SomeFunction();
    }

    public void SomeFunction() 
    {
        List<Person> loginStaff = new List<Person>(); 

        loginStaff.Add(new Person{FirstName = "John", LastName = "Doe"});

        _iViewLoginPanel.Staff = loginStaff;
    }

    public IViewLoginPanel ViewLoginPanel
    {
        get { return _iViewLoginPanel; }
    }
}

[TestFixture]
public class PresenterLoginPanelTests
{
    [Test]
    public void When_The_Presenter_Is_Created_Then_All_CP_Staff_Is_Added_To_Dropdown()
    {
        var _mockViewLoginPanel = new Mock<IViewLoginPanel>(MockBehavior.Strict);
        _mockViewLoginPanel.SetupAllProperties();

        PresenterLoginPanel target = new PresenterLoginPanel(_mockViewLoginPanel.Object);

        _mockViewLoginPanel.VerifySet(x => x.Staff = It.IsAny<List<Person>>());

        Assert.AreEqual(5, _mockViewLoginPanel.Object.Staff.Count);
    }

}

答案 1 :(得分:6)

您可以使用Moq本身轻松完成此操作(当您还没有对预期结果对象的引用时) - 只需使用It.Is(..)方法:

_mockViewLoginPanel.VerifySet(x => x.Staff = It.Is<List<Person>>(staff => staff.Count == 5));
_mockViewLoginPanel.VerifySet(x => x.Staff = It.Is<List<Person>>(staff => staff[0].FirstName == "John"));

答案 2 :(得分:1)

这将检查人员计数应该大于0,应该至少有一个非空的项目,并且至少有一个项目的名字等于Joe。如果你想比较对象,你将不得不添加一个比较器。

Assert.AreNotEqual(this._mockViewLoginPanel.Object.Staff.Count, 0);
Assert.AreNotEqual(this._mockViewLoginPanel.Object.Staff.All(x => x == null), true);
Assert.AreEqual(this._mockViewLoginPanel.Object.Staff.Any(x => x.FirstName == "Joe"), true);