我在使用带有Nsubstitue对象的.NET集合时遇到了问题。
我想知道这种行为的原因是什么,以及如何使用模型定义集合。
public class KeyTestClass : IKeyTestClass
{
public int Id { get; private set; }
public KeyTestClass()
{
Id = 1;
}
public override int GetHashCode()
{
return Id;
}
public int CompareTo(IKeyTestClass other)
{
return Id - other.Id;
}
public bool Equals(IKeyTestClass other)
{
return Id == other.Id;
}
public override bool Equals(object obj)
{
if (ReferenceEquals(null, obj)) return false;
if (ReferenceEquals(this, obj)) return true;
if (obj.GetType() != GetType()) return false;
return Equals((KeyTestClass)obj);
}
}
public interface IKeyTestClass : IComparable<IKeyTestClass>, IEquatable<IKeyTestClass>
{
int Id { get; }
}
public class KeyTestClass2 : IKeyTestClass2
{
}
public interface IKeyTestClass2
{
}
[TestClass]
public class ConsistencyRelatedTests
{
[TestMethod]
public void ValidateTestClass()
{
var dic = new Dictionary<IKeyTestClass,List<IKeyTestClass2>>();
// using new equals function defined by Nsubstittue.
var item1 = Substitute.For<IKeyTestClass>();
var item2 = Substitute.For<IKeyTestClass>();
item1.Id.Returns(1);
item2.Id.Returns(1);
Assert.IsTrue(item1.Equals(item2)); //false, not working
dic.Add(item1, new List<IKeyTestClass2>());
dic.Add(item2, new List<IKeyTestClass2>());
// Using real class equals method
var item3 = new KeyTestClass();
var item4 = new KeyTestClass();
Assert.IsTrue(item3.Equals(item4)); //working
dic.Add(item3, new List<IKeyTestClass2>());
dic.Add(item4, new List<IKeyTestClass2>());
}
}
答案 0 :(得分:1)
在此示例中,为dlink
实施了Equals()
。这并不意味着它适用于KeyTestClass
的所有实例。如果我们创建另一个类IKeyTestClass
并使用默认KeyTestClass2 : IKeyTestClass
,我们会得到完全相同的结果:
Equals
这就是当我们致电var item1 = new KeyTestClass2();
var item2 = new KeyTestClass2();
Assert.IsTrue(item1.Equals(item2)); // also fails, as expected
时NSubstitute所做的事情。它创建了一个实现接口的新类,因此它完全不知道Substitute.For<IKeyTestClass>()
实现。
根据您的目的,这里有一些选项。首先,您的KeyTestClass.Equals
适用于所有KeyTestClass.Equals
个实例,包括替代品,因此您可以使用它:
IKeyTestClass
其次,您可以在替代品上替换var item1 = new KeyTestClass();
var item2 = Substitute.For<IKeyTestClass>();
var item3 = Substitute.For<IKeyTestClass>();
item2.Id.Returns(1);
item3.Id.Returns(42);
Assert.IsTrue(item1.Equals(item2)); // Passes (as expected)
Assert.IsFalse(item1.Equals(item3)); // Passes (as expected)
方法(注意:不是IEquatable<IKeyTestClass>.Equals
,而是can cause problems)。
Object.Equals
在这种情况下,您可能还需要删除var item1 = Substitute.For<IKeyTestClass>();
var item2 = Substitute.For<IKeyTestClass>();
item1.Id.Returns(1);
item2.Id.Returns(1);
item1.Equals(item2).Returns(true);
Assert.IsTrue(item1.Equals(item2)); // Passes as expected
。我们还可以使用item2.Equals(item1)
(需要item1.Equals(Arg.Any<IKeyTestClass>).Returns(x => KeyTestClass.Equals(item1, x.Arg<IKeyTestClass>())
版本的static
逻辑提取)委托实际逻辑,并使用此调用配置每个替换。
另一个需要考虑的选择是尽可能使用真实的Equals
(或手工编码的测试双)。由于所有内容都回退到KeyTestClass
,因此.NET中的平等可能有点棘手,所以当平等是合同的关键部分时,需要注意这一点。