C# - Asserting two objects are equal in unit tests
You've got two different Board
instances, so your call to Assert.AreEqual
will fail. Even if their entire contents appear to be the same, you're comparing references, not the underlying values.
You have to specify what makes two Board
instances equal.
You can do it in your test:
Assert.AreEqual(expected.Rows.Count, actual.Rows.Count);
Assert.AreEqual(expected.Rows[0].Cells[0], actual.Rows[0].Cells[0]);
// Lots more tests of equality...
Or you can do it in your classes: (note I wrote this on-the-fly - you'll want to adjust this)
public class Board
{
public List<Row> Rows = new List<Row>();
public override bool Equals(object obj)
{
var board = obj as Board;
if (board == null)
return false;
if (board.Rows.Count != Rows.Count)
return false;
return !board.Rows.Where((t, i) => !t.Equals(Rows[i])).Any();
}
public override int GetHashCode()
{
// determine what's appropriate to return here - a unique board id may be appropriate if available
}
}
public class Row
{
public List<int> Cells = new List<int>();
public override bool Equals(object obj)
{
var row = obj as Row;
if (row == null)
return false;
if (row.Cells.Count != Cells.Count)
return false;
if (row.Cells.Except(Cells).Any())
return false;
return true;
}
public override int GetHashCode()
{
// determine what's appropriate to return here - a unique row id may be appropriate if available
}
}
Compare two class objects in C#
Assert.Equal
relies on the object's .Equals
method (see here). When creating your own classes, you have an option to override this method and add your own logic of comparing two objects equality (e.g., field by field equality checking).
If you do not override it, there is a default .Equals
inherited from Object
, which is equivalent to .ReferenceEquals
: it returns true if the two objects have the same reference and false otherwise. The only situation when the two objects have the same reference is when it's the same object.
In your case, you can either define the .Equals
override for your class (e.g., see here) or you can try to follow some of the advice given in this SO answer on how to perform deep equality checking of two objects. Third option is to create a separate class inherited from IEqualityComparer
, which will purely provide the equality checking logic for your object while not being a part of your class codebase (for example, see this article).
Swift Unit Testing: Checking for equality of two objects of the same class
Look at Equatable protocol. E.g.
extension MyClass: Equatable
{
static func ==(lhs: MyClass, rhs: MyClass) -> Bool
{
return (lhs.property1 == rhs.property1) && (lhs.allData == rhs.allData)
}
}
How to test equality of two objects in unit tests?
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).
C# Comparing Multiple Objects in Unit Testing without Overriding
So as not to override the Equals
method, you would typically create an implementation of IEqualityComparer<T>
where T
is the type you want to compare, in your case Product
.
In the comparer you have to implement the bool Equals(T x, T y)
and int GetHashCode(T obj)
methods.
Yours may look something like:
public class ProductComparer : IEqualityComparer<Product>
{
// Implement Equals and GetHashCode
}
Then you can use it like this:
var actual = new List<int>();
var expected = new List<int>();
var comparer = new ProductComparer();
Assert.That(actual, Is.EqualTo(expected).Using(comparer));
Proper way to compare object in a Unit test
Property-by-property comparison needs to be repeated in every test - so it's a good old code duplication, a test smell described in XUnitPatterns. Better have a proper equals()
.
Of course, you can add an utility method personEquals()
or even override Person.equals()
in runtime. For mocked class, you will probably have to. I personally stick to shorter code which is just one assertEquals()
when possible.
How to compare complex objects with NUnit Unit Test
There is a tool used in unit testing called Fluent Assertions
which is capable of doing such comparisons.
Note however
Objects are equivalent when both object graphs have equally named
properties with the same value, irrespective of the type of those
objects. Two properties are also equal if one type can be converted to
another and the result is equal. The type of a collection property is
ignored as long as the collection implements
System.Collections.IEnumerable and all items in the collection are
structurally equal. Notice that actual behavior is determined by the
global defaults managed by FluentAssertions.AssertionOptions.
using FluentAssertions;
//...
// Example 1
AMockObject a = new AMockObject();
AMockObject b = new AMockObject();
a.ShouldBeEquivalentTo(b); // Asserts that an object is equivalent to another object.
// Example 2
AMockObject a = new AMockObject() { Id = 1 };
AMockObject b = new AMockObject() { Id = 1 };
a.ShouldBeEquivalentTo(b); //Asserts that an object is equivalent to another object.
// Example 3
AMockObject a = new AMockObject() { Id = 1 };
a.Numbers.Add(1);
a.Numbers.Add(2);
a.Numbers.Add(3);
AMockObject b = new AMockObject() { Id = 1 };
b.Numbers.Add(1);
b.Numbers.Add(2);
b.Numbers.Add(3);
a.ShouldBeEquivalentTo(b)
a.Numbers.ShouldAllBeEquivalentTo(b.Numbers); // Asserts that a collection of objects is equivalent to another collection of objects.
Documentation here
Related Topics
Is There a Tool for Finding Unreferenced Functions (Dead, Obsolete Code) in a C# App
Fill an Array (Or Arraylist) from SQLdatareader
Download a File from Azure Devops Server Writes Wrong Data to The File
Webutility.HTMLdecode Vs Httputilty.HTMLdecode
Why Accessviolationexception Cannot Be Caught by .Net4.0
How to Allow an Anonymous User Access to Some Given Page in MVC
Deserialize JSON Object Sent from Android App to Wcf Webservice
Using Xmlarrayitem Attribute Without Xmlarray on Serializable C# Class
Webbrowser Control and JavaScript Errors
Generate PDF Based on HTML Code (Itextsharp, Pdfsharp)
How to Save Dlls in a Different Folder When Compiling in Visual Studio
How to Delete Cookies on an ASP.NET Website
Linq to Entities Generated SQL
ASP.NET Core MVC - Client-Side Validation for Custom Attribute
How to Change The Colour of The Line Below/Border of a Textbox (Entry)