NUnit 3 CollectionConstraint自定义IComparer <t>无效

时间:2018-02-18 13:17:17

标签: c# testing nunit

问题

如何为包含大量自定义界面引用的集合正确使用带有NUnit3集合约束的自定义IComparer<T>

我尝试了什么

我有一个返回IEnumerable<IInterface>实例的类,其中IInterface的定义如下:

public interface IInterface 
{    
    string PropertyOne { get; }

    string PropertyTwo { get; }    
}

我正在尝试使用NUnit3中的集合约束和自定义IComparer<T>,但它无效。要创建要测试的模拟对象,  我正在使用Moq。测试看起来大致如下:

[Test]
public void MyTest() 
{        
    var mockObject = new Mock<IInterface>();
    mockObject.Setup(x => x.PropertyOne).Returns("Foo");
    mockObject.Setup(x => x.PropertyTwo).Returns("Bar");

    var collection = myObject.Collection;

    Assert.That(collection, Contains.Item(mockObject).Using(this));
}

测试用例包含在继承自以下基类

的类中
public class TestBase : IComparer<IInterface> 
{
    public int Compare(IInterface one, IInterface two) { /* some code */ }
}

当我在上面的Compare方法上设置断点时,我发现NUnit完全忽略了我的比较器,选择在底层对象上使用ToString()实现,尽管事实如此它没有被界面暴露。

1 个答案:

答案 0 :(得分:0)

此处的问题是Nunit3IComparer<T>一起使用自定义Constraints的方式。如果提供了自定义比较器Nunit3,则将其存储在所谓的外部比较器列表中。每个IComparer<T>都将在内部存储为EqualityAdapter。稍后在比较点时,它会尝试将objects强制转换为T,以便决定是否应该使用自定义比较器。

我们在您的示例中,您有一个ICollection<IInterface>,但您创建的Constraint使用了Mock<IInterface>。显然IInterface无法与Mock<IInterface>进行比较。

我个人发现这种误导,因为问题将在运行时弹出,而不是在编译时。以下示例将解释该问题:

错误的使用示例

//notice that Constraints is created for the int but IComparer<string> is used
List<string> strs = new List<string> {"1", "2", "3"};
Assert.That(strs, Contains.Item(5).Using((IComparer<string>) comparer));

正确的用法示例

//notice that Constraints is created for the string and IComparer<string> is used
List<string> strs = new List<string> {"1", "2", "3"};
Assert.That(strs, Contains.Item("5").Using((IComparer<string>) comparer));