Date:

Share:

Use custom Equality comparers in Nunit tests | Code4IT

Related Articles

When writing unit tests, you should check that the result returned by a method is equal to the one you expect.

[Test]
public void Reverse_Should_BeCorrect()
{
  string input = "hello";
  string result = MyUtils.Reverse(input);

  Assert.That(result, Is.EqualTo("olleh"));
}

This approach works pretty well, unless you want to check values ​​on complex types without equality checks.

public class Player
{
  public int Id { get; set; }
  public string UserName { get; set; }
  public int Score { get; set; }
}

Let’s create a dummy method that clones a player:

public static Player GetClone(Player source)
  => new Player
    {
      Id = source.Id,
      UserName = source.UserName,
      Score = source.Score
    };

And call it like this:

[Test]
public void GetClone()
{
  var originalPlayer = new Player { Id = 1, UserName = "me", Score = 1 };

  var clonedPlayer = MyUtils.GetClone(originalPlayer);

  Assert.That(clonedPlayer, Is.EqualTo(originalPlayer));
}

Even if from a logical point of view originalPlayer and clonedPlayer Equal, they are not the same: the test will fail!

Luckily, we can specify the rules of comparison!

Equality function: great for simple tests

Say we don’t want to check that all values ​​match. We only care Id and UserName.

When we only have a few fields to check, we can use a function to indicate that two items are equal:

[Test]
public void GetClone_WithEqualityFunction()
{
  var originalPlayer = new Player { Id = 1, UserName = "me", Score = 1 };

  var clonedPlayer = MyUtils.GetClone(originalPlayer);

  Assert.That(clonedPlayer, Is.EqualTo(originalPlayer).Using<Player>(
    (Player a, Player b) => a.Id == b.Id && a.UserName == b.UserName)
    );
}

Obviously, if the method becomes unreadable, you can change the comparison function like this:

[Test]
public void GetClone_WithEqualityFunction()
{
  var originalPlayer = new Player { Id = 1, UserName = "me", Score = 1 };

  var clonedPlayer = MyUtils.GetClone(originalPlayer);

  Func<Player, Player, bool> comparer = (Player a, Player b) => a.Id == b.Id && a.UserName == b.UserName;

  Assert.That(clonedPlayer, Is.EqualTo(originalPlayer).Using<Player>(comparer));
}

EqualityComparer class: Best for complex scenarios

If you have a complex scenario to validate, you can create a custom class that implements the IEqualityComparer interface. Here, you need to apply two methods: Equals and GetHashCode.

instead of just applying the same notation within Equals method, we will try another approach: we will use GetHashCode To determine how to identify a player, by creating a string that serves as a simple identifier, then use the HashCode of the resulting string to actually compare:

public class PlayersComparer : IEqualityComparer<Player>
{
    public bool Equals(Player? x, Player? y)
    {
        return
            (x is null && y is null)
            ||
            GetHashCode(x) == GetHashCode(y);
    }

    public int GetHashCode([DisallowNull] Player obj)
    {
        return $"{obj.Id}-{obj.UserName}".GetHashCode();
    }
}

Of course, I also added a check to cancel cancellation: (x is null && y is null).

Now we can create a new instance of PlayersComparer and use it to check if two players are equal:

[Test]
public void GetClone_WithEqualityComparer()
{
    var originalPlayer = new Player { Id = 1, UserName = "me", Score = 1 };

    var clonedPlayer = MyUtils.GetClone(originalPlayer);

    Assert.That(clonedPlayer, Is.EqualTo(originalPlayer).Using<Player>(new PlayersComparer()));
}

Of course, you can customize the Equals A method to use each condition to verify the equivalence of two cases, according to your business rules. For example, two vectors can be said to be equal if they have exactly the same length and direction, even though the starting and ending points are different.

❓ A question for you: Where would you put the equality check: in the production code or in the testing project?

finishing

As we learned in this article, there are smarter ways to check if two objects are equal than just comparing each field one by one.

I hope you enjoyed this article! Let’s keep in touch Twitter or LinkedIn! 🤜🤛

Happy coding!

🐧

.

Source

Popular Articles