Assert to compare two lists of objects C# - c#

I am currently trying to learn how to use unit testing, and I have created the actual list of 3 animal objects and the expected list of 3 animal objects. The question is how do I Assert to check the lists are equal? I have tried CollectionAssert.AreEqual and Assert.AreEqual but to no avail. Any help would be appreciated.
The test method:
[TestMethod]
public void createAnimalsTest2()
{
animalHandler animalHandler = new animalHandler();
// arrange
List<Animal> expected = new List<Animal>();
Animal dog = new Dog("",0);
Animal cat = new Cat("",0);
Animal mouse = new Mouse("",0);
expected.Add(dog);
expected.Add(cat);
expected.Add(mouse);
//actual
List<Animal> actual = animalHandler.createAnimals("","","",0,0,0);
//assert
//this is the line that does not evaluate as true
Assert.Equals(expected ,actual);
}

That is correct, as the lists might look the same, they are 2 different objects containing the same data.
In order to compare lists, you should use the CollectionAssert
CollectionAssert.AreEqual(expected, actual);
That should do the trick.

Just incase someone comes across this in the future, the answer was I had to create an Override, IEqualityComparer as described below:
public class MyPersonEqualityComparer : IEqualityComparer<MyPerson>
{
public bool Equals(MyPerson x, MyPerson y)
{
if (object.ReferenceEquals(x, y)) return true;
if (object.ReferenceEquals(x, null)||object.ReferenceEquals(y, null)) return false;
return x.Name == y.Name && x.Age == y.Age;
}
public int GetHashCode(MyPerson obj)
{
if (object.ReferenceEquals(obj, null)) return 0;
int hashCodeName = obj.Name == null ? 0 : obj.Name.GetHashCode();
int hasCodeAge = obj.Age.GetHashCode();
return hashCodeName ^ hasCodeAge;
}
}

I am of the opinion that implementing the IEqualityComparer (Equals() and GetHashCode()) for only testing purpose is a code smell. I would rather use the following assertion method, where you can freely define that on which properties you want to do the assertions:
public static void AssertListEquals<TE, TA>(Action<TE, TA> asserter, IEnumerable<TE> expected, IEnumerable<TA> actual)
{
IList<TA> actualList = actual.ToList();
IList<TE> expectedList = expected.ToList();
Assert.True(
actualList.Count == expectedList.Count,
$"Lists have different sizes. Expected list: {expectedList.Count}, actual list: {actualList.Count}");
for (var i = 0; i < expectedList.Count; i++)
{
try
{
asserter.Invoke(expectedList[i], actualList[i]);
}
catch (Exception e)
{
Assert.True(false, $"Assertion failed because: {e.Message}");
}
}
}
In action it would look like as follows:
public void TestMethod()
{
//Arrange
//...
//Act
//...
//Assert
AssertAnimals(expectedAnimals, actualAnimals);
}
private void AssertAnimals(IEnumerable<Animal> expectedAnimals, IEnumerable<Animal> actualAnimals)
{
ListAsserter.AssertListEquals(
(e,a) => AssertAnimal(e,a),
expectedAnimals,
actualAnimals);
}
private void AssertAnimal(Animal expected, Animal actual)
{
Assert.Equal(expected.Name, actual.Name);
Assert.Equal(expected.Weight, actual.Weight);
//Additional properties to assert...
}
I am using XUnit for the simple Assert.True(...) and Assert.Equals(), but you can use any other unit test library for that. Hope it helps someone! ;)

I modified method AssertListEquals() and used standard Assert.All()
public static void AssertListEquals<TE, TA>(IEnumerable<TE> expected, IEnumerable<TA> actual, Action<TE, TA> asserter)
{
if (expected == null && actual == null) return;
Assert.NotNull(expected);
Assert.NotNull(actual);
Assert.True(
actual.Count() == expected.Count(),
$"Lists have different sizes. Expected list: {expected.Count()}, actual list: {actual.Count()}");
var i = 0;
Assert.All(expected, e =>
{
try
{
asserter(e, actual.Skip(i).First());
}
finally
{
i++;
}
});
}

Related

Avoiding duplicates in a HashSet of custom types in C#

I have the following custom class deriving from Tuple:
public class CustomTuple : Tuple<List<string>, DateTime?>
{
public CustomTuple(IEnumerable<string> strings, DateTime? time)
: base(strings.OrderBy(x => x).ToList(), time)
{
}
}
and a HashSet<CustomTuple>. The problem is that when I add items to the set, they are not recognised as duplicates. i.e. this outputs 2, but it should output 1:
void Main()
{
HashSet<CustomTuple> set = new HashSet<CustomTuple>();
var a = new CustomTuple(new List<string>(), new DateTime?());
var b = new CustomTuple(new List<string>(), new DateTime?());
set.Add(a);
set.Add(b);
Console.Write(set.Count); // Outputs 2
}
How can I override the Equals and GetHashCode methods to cause this code to output a set count of 1?
You should override GetHashCode and Equals virtual methods defined in System.Object class.
Please remember that:
If two objects are logically "equal" then they MUST have the same hash code!
If two objects have the same hashcode, then it is not mandatory to have your objects equal.
Also, i've noticed an architectural problem in your code:
List is a mutable type but overriding Equals and GetHashCode usually makes your class logically to behave like a value type. So having "Item1" a mutable type and behaving like a value type is very dangerous. I suggest replacing your List with a ReadOnlyCollection . Then you would have to make a method that checks whether two ReadOnlyCollections are Equal.
For the GetHashCode () method, just compose a string from all string items found in Item1 then append a string that represents the Hash code for datetime then finally call on the concatenated result the "GetHashCode ()" overrided on string method. So normally you would have:
override int GetHashCode () {
return (GetHashCodeForList (Item1) + (Item2 ?? DateTime.MinValue).GetHashCode ()).GetHashCode ();
}
And the GetHashCodeForList method would be something like this:
private string GetHashCodeForList (IEnumerable <string> lst) {
if (lst == null) return string.Empty;
StringBuilder sb = new StringBuilder ();
foreach (var item in lst) {
sb.Append (item);
}
return sb.ToString ();
}
Final note: You could cache the GetHashCode result since it is relative expensive to get and your entire class would became immutable (if you replace List with a readonly collection).
A HashSet<T> will first call GetHashCode, so you need to work on that first. For an implementation, see this answer: https://stackoverflow.com/a/263416/1250301
So a simple, naive, implementation might look like this:
public override int GetHashCode()
{
unchecked
{
int hash = 17;
hash = hash * 23 + this.Item2.GetHashCode();
foreach (var s in this.Item1)
{
hash = hash * 23 + s.GetHashCode();
}
return hash;
}
}
However, if your lists are long, then this might not be efficient enough. So you'll have to decide where to compromise depending on how tolerant you are of collisions.
If the result of GetHashCode for two items are the same, then, and only then, will it call Equals. An implementation of Equals is going to need to compare the items in the list. Something like this:
public override bool Equals(object o1)
{
var o = o1 as CustomTuple;
if (o == null)
{
return false;
}
if (Item2 != o.Item2)
{
return false;
}
if (Item1.Count() != o.Item1.Count())
{
return false;
}
for (int i=0; i < Item1.Count(); i++)
{
if (Item1[i] != o.Item1[i])
{
return false;
}
}
return true;
}
Note that we check the date (Item2) first, because that's cheap. If the date isn't the same, we don't bother with anything else. Next we check the Count on both collections (Item1). If they don't match, there's no point iterating the collections. Then we loop through both collections and compare each item. Once we find one that doesn't match, we return false because there is no point continuing to look.
As pointed out in George's answer, you also have the problem that your list is mutable, which will cause problems with your HashSet, for example:
var a = new CustomTuple(new List<string>() {"foo"} , new DateTime?());
var b = new CustomTuple(new List<string>(), new DateTime?());
set.Add(a);
set.Add(b);
// Hashset now has two entries
((List<string>)a.Item1).Add("foo");
// Hashset still has two entries, but they are now identical.
To solve that, you need to force your IEnumerable<string> to be readonly. You could do something like:
public class CustomTuple : Tuple<IReadOnlyList<string>, DateTime?>
{
public CustomTuple(IEnumerable<string> strings, DateTime? time)
: base(strings.OrderBy(x => x).ToList().AsReadOnly(), time)
{
}
public override bool Equals(object o1)
{
// as above
}
public override int GetHashCode()
{
// as above
}
}
This is is what I went for, which outputs 1 as desired:
private class CustomTuple : Tuple<List<string>, DateTime?>
{
public CustomTuple(IEnumerable<string> strings, DateTime? time)
: base(strings.OrderBy(x => x).ToList(), time)
{
}
public override bool Equals(object obj)
{
if (obj == null || GetType() != obj.GetType())
{
return false;
}
var that = (CustomTuple) obj;
if (Item1 == null && that.Item1 != null || Item1 != null && that.Item1 == null) return false;
if (Item2 == null && that.Item2 != null || Item2 != null && that.Item2 == null) return false;
if (!Item2.Equals(that.Item2)) return false;
if (that.Item1.Count != Item1.Count) return false;
for (int i = 0; i < Item1.Count; i++)
{
if (!Item1[i].Equals(that.Item1[i])) return false;
}
return true;
}
public override int GetHashCode()
{
int hash = 17;
hash = hash*23 + Item2.GetHashCode();
return Item1.Aggregate(hash, (current, s) => current*23 + s.GetHashCode());
}
}

NSubstitute - Check arguments passed to method

We are currently in the process of moving from RhinoMocks to NSubstitute.
I have a method that takes an object of type DatabaseParams. This class has the following structure (simplified):
public class DatabaseParams
{
public string StoredProcName { get; private set; }
public SqlParameter[] Parameters { get; private set; }
public DatabaseParams(string storeProcName, SqlParameter[] spParams)
{
StoredProcName = storeProcName;
Parameters = spParams;
}
}
I have the following method I want to check the arguments being passed to it are correct:
public interface IHelper
{
Task<object> ExecuteScalarProcedureAsync(DatabaseParams data);
}
How do I test that an instance of DatabaseParams was passed into that method with the correct values?
I could do this in RhinoMocks with something like this:
helperMock.Expect(m => m.ExecuteScalarProcedureAsync(Arg<DatabaseHelperParameters>.Matches(
p => p.StoredProcName == "up_Do_Something"
&& p.Parameters[0].ParameterName == "Param1"
&& p.Parameters[0].Value.ToString() == "Param1Value"
&& p.Parameters[1].ParameterName == "Param2"
&& p.Parameters[1].Value.ToString() == "Param2Value"
))).Return(Task.FromResult<DataSet>(null));
The helperMock is mocking the interface IHelper that contains the ExecuteScalarProcedureAsync method.
I've figured out the answer myself.
NSubstitute just needs to use the .Received() call and then when you specify your argument to the method. You can specify the argument matching as a predicate.
For example:
helperMock.Received().ExecuteScalarProcedureAsync(Arg.Is<DatabaseParams>(
p => p.StoredProcName == "up_Do_Something"
&& p.Parameters[0].ParameterName == "Param1"
&& p.Parameters[0].Value.ToString() == "Param1Value"
&& p.Parameters[1].ParameterName == "Param2"
&& p.Parameters[1].Value.ToString() == "Param2Value"));
An alternative is to use Do (see https://nsubstitute.github.io/help/actions-with-arguments/). I prefer this as it lets you call assertions against specific properties of the arguments, which gives you better feedback on which specific properties of the argument object are incorrect. For example:
StoredProc sp = null; // Guessing the type here
// Setup Do to capture arg
helperMock.ExecuteScalarProcedureAsync(Arg.Do<DatabaseParams>(p => sp = p));
// Call method
helperMock.ExecuteScalarProcedureAsync(dbParams);
// NUnit assertions, but replace with whatever you want.
Assert.AreEqual("up_Do_Something", sp.StoredProcName);
Assert.AreEqual("Param1", p.Parameters[0].ParameterName);
Assert.AreEqual("Param1Value", p.Parameters[0].Value.ToString());
Assert.AreEqual("Param2", p.Parameters[1].ParameterName);
Assert.AreEqual("Param2Value", p.Parameters[1].Value.ToString());
A bit late for the party, but ran into the same need.
I am working with mockito in java, and they have an Argument capture helper that I like.
It is basically the same as #Castrohenge answer
So here is my NSubstitute implementation.
public interface IFoo
{
void DoSomthing(string stringArg);
}
Argument capture class
public class ArgCapture<T>
{
private List<T> m_arguments = new List<T>();
public T capture()
{
T res = Arg.Is<T>(obj => add(obj)); // or use Arg.Compat.Is<T>(obj => add(obj)); for C#6 and lower
return res;
}
public int Count
{
get { return m_arguments.Count; }
}
public T this[int index]
{
get { return m_arguments[index]; }
}
public List<T> Values {
get { return new List<T>(m_arguments);}
}
private bool add(T obj)
{
m_arguments.Add(obj);
return true;
}
}
And the usage test case
[Test]
public void ArgCaptureTest()
{
IFoo foo1 = Substitute.For<IFoo>();
ArgCapture<string> stringArgCapture = new ArgCapture<string>();
foo1.DoSomthing("firstCall");
foo1.DoSomthing("secondCall");
foo1.Received(2).DoSomthing(stringArgCapture.capture());
Assert.AreEqual(2,stringArgCapture.Count);
Assert.AreEqual("firstCall",stringArgCapture[0]);
Assert.AreEqual("secondCall", stringArgCapture[1]);
}

Code Contracts - ForAll - What is supported by static verification

There are numerous information that static checking of Contract.ForAll has only limited or no support.
I did lot of experimenting and found it can work with:
Contract.ForAll(items, i => i != null)
Contract.ForAll(items, p) where p is of type Predicate<T>
it cannot work with:
Field access
Property access
Method group (I think delegate is allocated here anyway)
Instance method call
My questions are:
What are other types of code that ForAll can work with?
Does the Code Contracts undertand that after Contract.ForAll(items, i => i != null) is proven, that when taking one item from the list later in code (i.e. by indexing), the item is not null?
Here is full test code:
public sealed class Test
{
public bool Field;
public static Predicate<Test> Predicate;
[Pure]
public bool Property
{
get { return Field; }
}
[Pure]
public static bool Method(Test t)
{
return t.Field;
}
[Pure]
public bool InstanceMethod()
{
return Field;
}
public static void Test1()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i != null));
Contract.Assert(Contract.ForAll(items, i => i != null)); // OK
}
public static void Test2()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, Predicate));
Contract.Assert(Contract.ForAll(items, Predicate)); // OK
}
public static void Test3()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i.Field));
Contract.Assert(Contract.ForAll(items, i => i.Field)); // assert unproven
}
public static void Test4()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i.Property));
Contract.Assert(Contract.ForAll(items, i => i.Property)); // assert unproven
}
public static void Test5()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, Method));
Contract.Assert(Contract.ForAll(items, Method)); // assert unproven
}
public static void Test6()
{
var items = new List<Test>();
Contract.Assume(Contract.ForAll(items, i => i.InstanceMethod()));
Contract.Assert(Contract.ForAll(items, i => i.InstanceMethod()));// assert unproven
}
}
I was not able to find more working expressions, in fact I found that even Contract.ForAll(items, i => i != null) is not working reliably (but it understands that the item is not null when later used inside foreach in the same function). Finally, I gave up on possibility to use more complex ForAll contracts with static checker.
Instead I devised a way to control which contract are for static checker, and which are for runtime checker. I present this method here, in hope that it might be useful for people interesting in original question. The benefit is ability to be write more complex contracts, which can be checked at runtime only, and leave only easily provable contracts for static checker (and easily keep warnings at low count).
For that, 2 builds Debug are needed (If you don't already have them), Debug and Debug + Static Contracts, The Debug build has conditional compilation symbol MYPROJECT_CONTRACTS_RUNTIME defined. In this way it receives all Contract. and RtContract. contracts. Other builds receive only Contract. contracts.
public static class RtContract
{
[Pure] [ContractAbbreviator] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")]
public static void Requires(bool condition)
{
Contract.Requires(condition);
}
[Pure] [ContractAbbreviator] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")]
public static void Ensures(bool condition)
{
Contract.Ensures(condition);
}
[Pure] [Conditional("MYPROJECT_CONTRACTS_RUNTIME")]
public static void Assume(bool condition)
{
Contract.Assume(condition);
}
}
public class Usage
{
void Test (int x)
{
Contract.Requires(x >= 0); // for static and runtime
RtContract.Requires(x.IsFibonacci()); // for runtime only
}
}
By decompiling mscorelib.dll System.Diagnostics.Contracts we can easely see how Contract.ForAll is built: It takes collection and predicate.
public static bool ForAll<T>(IEnumerable<T> collection, Predicate<T> predicate)
{
if (collection == null)
{
throw new ArgumentNullException("collection");
}
if (predicate == null)
{
throw new ArgumentNullException("predicate");
}
foreach (T current in collection)
{
if (!predicate(current))
{
return false;
}
}
return true;
}
So when you say Contract.ForAll(items, i => i.Field) in this case i => i.Field is predicate
Then by following your example in all test methods, we can see that you provide an empty list to Contract.ForAll method which will return true as it will never enter the foreach block.
Taking it further, if you add item to your list
var items = new List<Test>() {new Test()}; and run the test again it will return false as your public bool Field; is false by default
The goal of Contract.ForAll is to
Determines whether all the elements in a collection exist within a
function
So my conclusion is that it is not about Contarct.ForAll can't work with something, it is rather at least one element in your collection returns false or is null

Assert two different types of enumerations are equivalent

I have an NUnit unit test which I have two collections of different types which I want to assert are equivalent.
class A { public int x; }
class B { public string y; }
[Test]
public void MyUnitTest()
{
var a = GetABunchOfAs(); // returns IEnumerable<A>
var b = GetABunchOfBs(); // returns IEnumerable<B>
Assert.IsPrettySimilar(a, b, (argA, argB) => argA.ToString() == argB);
}
where Assert.IsPrettySimilar is defined like such
public static void IsPrettySimilar<T1, T2>(
IEnumerable<T1> left,
IEnumerable<T2> right,
Func<T1, T2, bool> predicate)
{
using (var leftEnumerator = left.GetEnumerator())
using (var rightEnumerator = right.GetEnumerator())
{
while (true)
{
var leftMoved = leftEnumerator.MoveNext();
if (leftMoved != rightEnumerator.MoveNext())
{
Assert.Fail("Enumerators not of equal size");
}
if (!leftMoved)
{
break;
}
var isMatch = predicate(leftEnumerator.Current,
rightEnumerator.Current);
Assert.IsTrue(isMatch);
}
}
}
My question is, is there a more idiomatic way of doing the above with the existing methods in NUnit? I already looked at CollectionAssert and there's nothing matching what I want to do.
My description of "equivalent" in this case is:
1) Collections must be of same size
2) Collections must be in same logical order
3) Some predicate must be used to determine equivalence between matching items.
Let's think what you are trying to test. You are not trying to test that objects from first sequence are same as objects from second sequence. They can be very different. So, word similar is very vague here. What you really trying to test here, is that some projection of first sequence is equal to other projection of second sequence. And NUnit already have such functionality:
CollectionAssert.AreEqual(bunchOfAs.Select(a => a.ToString()),
bunchOfBs.Select(b => b));
Thus you are projecting both sequences to get particular data, then you can give nice names for these two projections, which will make your test readable to others. You have some hidden business logic here, which does not have explanation in code - you don't explain why you making such projections. So, nice names of projection results will explain your intent. E.g:
var expectedNames = employees.Select(u => u.Login);
var actualNames = customers.Select(c => c.Name);
CollectionAssert.AreEqual(expectedNames, actualNames);
That is much cleaner for me than
Assert.IsPrettySimilar(employees, customers, (e, c) => u.Login == c.Name);
I know you looked into CollectionAssert, however, I have found a strategy like this very useful in my own tests.
Overriding ToString and Equals on the objects makes this test pass.
[TestFixture]
public class Class1
{
[Test]
public void MyUnitTest()
{
var a = GetABunchOfAs(); // returns IEnumerable<A>
var b = GetABunchOfBs(); // returns IEnumerable<B>
CollectionAssert.AreEqual(a, b.OrderBy(x => x.y));
}
public List<A> GetABunchOfAs()
{
return new List<A>
{
new A() {x = 1},
new A() {x = 2},
new A() {x = 3},
new A() {x = 4}
};
}
public List<B> GetABunchOfBs()
{
return new List<B>
{
new B() {y = "4"},
new B() {y = "1"},
new B() {y = "2"},
new B() {y = "3"},
};
}
}
public class A
{
public int x;
public override bool Equals(object obj)
{
return obj.ToString().Equals(x.ToString());
}
public override string ToString()
{
return x.ToString();
}
}
public class B
{
public string y;
public override string ToString()
{
return y;
}
public override bool Equals(object obj)
{
return obj.ToString().Equals(y);
}
}
I deliberately left GetABunchOfBs out of order, however the test still passes.
It looks like Sergey's answer is the one I'm looking for (which was to see whether NUnit already has a facility to do what I want). However, this is the solution I ended up with, which is closer to the implementation I want.
public static class EnumerableAssert
{
public static void AreEquivilent<TExpected, TActual>(IEnumerable<TExpected> expected, IEnumerable<TActual> actual, Func<TExpected, TActual, bool> predicate)
{
if (ReferenceEquals(expected, actual))
{
return;
}
using (var expectedEnumerator = expected.GetEnumerator())
using (var actualEnumerator = actual.GetEnumerator())
{
while (true)
{
var expectedMoved = expectedEnumerator.MoveNext();
if (expectedMoved != actualEnumerator.MoveNext())
{
Assert.Fail("Expected and Actual collections are of different size");
}
if (!expectedMoved)
{
return;
}
Assert.IsTrue(predicate(expectedEnumerator.Current, actualEnumerator.Current));
}
}
}
}

VS2012 assert helper function - test runner should not track in my function

During testing I have several Assert helper functions specific to the project. For example, I have to often check whether two IEnumerables are equivalent (exactly same content by reference, not regarding the order). So have a static class for these. E.g.:
internal static class MyAssert
{
public static void AreEquivalent<T>(IEnumerable<T> enumerable1, IEnumerable<T> enumerable2)
{
bool val = false;
if (enumerable2 == null)
{
val = !enumerable1.Any();
} else {
var list1 = enumerable1.ToList();
var list2 = enumerable2.ToList();
val = (list1.Count == list2.Count && list1.Intersect(list2).Count() == list2.Count());
}
Assert.IsTrue(val);
}
}
Then if I use MyAssert.AreEquivalent(enumer1, enumer2);, and it fails, then the whole stack trace is shown inside the helper function. I would like to miss it, so if a developer comes, and sees the source of assert, he only sees that the MyAssert thing failed, but he does not see where was the problem inside my helper function (he cannot do anything with Assert.IsTrue(val)).
I know that it can be done with Assert.IsTrue(MyCollHelper.AreEquivalent(enumer1, enumer2)), but this is not as readebly as the previous.
I not sure that I understand you correctly. If you or the developer will see which part of your method causes the error than use Assert.Fail(). I didn't test it:
internal static class MyAssert
{
public static void AreEquivalent<T>(IEnumerable<T> enumerable1, IEnumerable<T> enumerable2)
{
bool val = false;
if (enumerable2 == null)
{
val = !enumerable1.Any();
if (val == false)
{
Assert.Fail("enumerable2 is empty, enumerable1 is not");
}
}
else if (enumerable1 == null)
{
val = !enumerable2.Any();
if (val == false)
{
Assert.Fail("enumerable1 is empty, enumerable2 is not");
}
}
else
{
var list1 = enumerable1.ToList();
var list2 = enumerable2.ToList();
if (list1.Count != list2.Count)
{
Assert.Fail("Count result is not the same");
}
if (list1.Intersect(list2).Count() != list2.Count())
{
Assert.Fail("count of Intersect enumerable1 is not the same as enumerable2 count");
}
}
}
}
Unfortunately this is impossible now.

Categories