4

I have a project in which I am receiving objects as DTOs and I am converting them to View-Models. In order to do this conversion I decided to make custom converters which does some calculation in order to convert from DTOs properties to View-Models. After all of these were ready, and the conversion was working, I wanted to add some unit tests to the conversion in order to make it more stable (I know this does not respect TDD, but this is what I managed to do).

The problem comes when I want tests to verify the equality of two View-Models

Assert.AreEqual(expected, actual);

Because none of the View-Models define Equals method, and they will never be equal as reference. There are some approaches I thought about and found to compare these objects:

  1. To define the Equals method. But I don't know if it is a good practice to define it, only for testing purposes. And if I define it, it will be recommended to define the GetHashCode method too, so I don't feel that this solution is the best.

  2. Another possibility I thought is to implement IEqualityComparer<T> in the test project, to isolate the comparison logic from the main conversion project, or even extracting this into a 3rd project, so the conversion module could use it in future if it's necessary. This implementation looks good, but I don't know if it's worth to add another project with many classes, which should be tested too.

  3. The 3rd approach I found on a Stack Overflow question, which looks interesting, is to serialize both objects and compare the strings. The problem is that I don't know if this is a good practice of programming.

Which of these would be the best way to compare the objects? Am I missing some approaches that could be more efficient?

Note: The View-Models are complex objects, and I can not change the way of conversion to other technologies.

Community
  • 1
  • 1
meJustAndrew
  • 6,011
  • 8
  • 50
  • 76
  • Seems like you're already outlined the pros and cons - I would not trust serialization unless they are the same type - there are many reasons why two types with the same properties could serialize differently. – D Stanley Jul 14 '16 at 19:45
  • @DStanley they will always be the same type, or so it seems right now, although if I am making a method with generic type parameter as it is `Equals` from `IEqualityComparer` which receives both objects and instead of simple comparison, to serialize them and return their string comparison? would it be enough stable this way? – meJustAndrew Jul 14 '16 at 20:41
  • @DStanley I can see you have voted to close this question, as being too broad, but I have read the help center what means to be too broad, and I don't think this question fits in that section as it's answers do not require wirting the hole content of a book or not even really long answers. Please consider that many other programming questions can have multiple answers, wich are good, but none of these makes them *too broad*. Thank you! – meJustAndrew Jul 15 '16 at 11:50
  • Actually I (and 4 others) voted to close it as opinion-based because all of your proposed solutions are technically viable, so the "best" is generally a matter of opinion. In any case, you have accepted an answer so "no harm no foul". – D Stanley Jul 15 '16 at 13:13
  • @DStanley I understand this, but any other suggestions would have been wellcomed, and I don't think it would be any harm to keep this question opened. I still respect your decision! – meJustAndrew Jul 15 '16 at 13:23

2 Answers2

3

I really like Fluent Assertions's ShouldBeEquivalentTo method.

actual.ShouldBeEquivalentTo(expected);

By default, this "just works", supposing both the objects you pass in are structurally equivalent, but you can provide additional arguments to customize how you want it to do the comparison. For example, if you just want to check the equivalence of a few pieces of the object, you could say:

actual.ShouldBeEquivalentTo(new {
    expected.Name,
    expected.Description,
    expected.Code
}, options =>
    options.ExcludingMissingMembers);
StriplingWarrior
  • 151,543
  • 27
  • 246
  • 315
3

Your second approach is much better than the other two, because it keeps tests-specific code together with unit tests, and also because it lets you change your definition of what it means for two View-Models to be equal.

It's hardly worth it to move equality comparers into a separate project, though: if you intend to share equality comparison logic, then you might as well put it into your objects. If, on the other hand, it is designed only for testing, then you should keep it together with the tests (i.e. use your approach #1).

The approach based on serialization is too fragile, because it relies on an unrelated feature (i.e. serialization) to test the feature that you are actually testing (i.e. conversion).

Sergey Kalinichenko
  • 714,442
  • 84
  • 1,110
  • 1,523