使用NSubstitue代理对象的C#集合覆盖等于

时间:2017-06-28 20:44:29

标签: c# nsubstitute

我在使用带有Nsubstitue对象的.NET集合时遇到了问题。

  1. 我有一个基类,我实现了Equals(object),CompareTo函数
  2. 在测试中,我为这个基类创建了两个精确的Nsubstitue对象代理。
  3. 将对象放入集合后,集合显示这两个对象代理是两个不同的对象。
  4. 我想知道这种行为的原因是什么,以及如何使用模型定义集合。

    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>());
        }
    
    }
    

1 个答案:

答案 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中的平等可能有点棘手,所以当平等是合同的关键部分时,需要注意这一点。