Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Unit Test: Clone and equality

I am writing Unit Tests and thinking about the scenario of a type that implements IClonable. So of course I want to have a Unit Test that tests the Clone() method.

[Test]
public void CloneObject()
{
    MyType original = new MyType();
    MyType clone = (MyType)original.Clone();

    // Assert for equality
}

So my first task it to have an Assert for the equality. I see following options:

  • going through all properties (fields) of MyType and check them one by one
  • override Equals() in MyType to let MyType say if two instances are equal (consider that sometimes equality for tests is considered different of equality for production code)
  • Check with some kind of serialization if the instances are equal (for that scenario MyType would have to be [Serializable], but that sometimes is hard to do if it has e.g. Interface Properties)
  • ...??

For the first two I can setup my tests and they work well. But what if I change MyType and add an additional property? If Clone() doesn't copy this and I don't add it in the list of checked properties or the equals method my test still passes even if the property does not get copied.

How do you solve this kind of tests?

like image 441
joerg Avatar asked Aug 11 '15 09:08

joerg


2 Answers

You can use the FluentAssertions library (a TDD must-have, IMO), which has a ShouldBeEquivalent method that performs graph comparison of the two objects:

original.ShouldBeEquivalentTo(clone);

The comparison algorithm can be customized via the optional options parameter; see their wiki for detailed info.

To make the test future-proof (i.e., it breaks when new properties are added to the class, but not to the Clone method), you might want to test cloning an object with all its properties set to random non-default values. AutoFixture can do that for you.

// Arrange
var fixture = new Fixture();
var original = fixture.Create<MyType>();

// Act
var clone = original.Clone();

// Assert
clone.ShouldBeEquivalentTo(original);

Useful links:

  • FluentAssertions Cheat-Sheet
  • AutoFixture Cheat-Sheet (it's a bit outdated, but it demonstrates most of its basic features)
like image 95
dcastro Avatar answered Nov 15 '22 18:11

dcastro


I would favor implementing Equals(). I see no reason why Equals() needs to produce different results in production vs. in tests.

If you don't do that, your Assert could call object.ReferenceEquals(), as follows:

Assert.IsTrue(object.ReferenceEquals(expectedObject, objectInHand));
like image 28
Jeff Prince Avatar answered Nov 15 '22 20:11

Jeff Prince