Override ToString in NUnit without access to source code - c#

I have a class, Foo, from a third party library that I check for equality against another instance using NUnit,
Assert.AreEqual(foo1, foo2);
When the objects are different I get the expected failure,
Expected: Foo
But was: Foo
But the error message isn't very helpful. I know NUnit uses ToString to show the error message but I can't override that here.
Does NUnit provide an API to override this behaviour so I can supply my own ToString implementation? I can't see anything on the Assert.AreEqual and Assert.That APIs

You can add specific formatting code for any Type and NUnit will use it. See https://github.com/nunit/docs/wiki/TestContext#addformatter
This feature was added in NUnit 3.2.

This may not be a great approach, but you could wrap the values inside of another class, and override ToString() there. For instance, in your test fixture, create the following private class:
private class ValueWrapper
{
private readonly OtherClass _wrapped;
public ValueWrapper(OtherClass wrapped)
{
_wrapped = wrapped;
}
public override bool Equals(object obj)
{
// Compare the wrapped objects for equality.
// This needs some beefing up for null checks, type checks, etc.
return _wrapped.Equals(obj._wrapped);
}
public override string ToString()
{
return "whatever you like";
}
}
With this wrapper class in hand, you could then wrap your expected & actual values and pass this into the asserts. For a CollectionAssert, you'd do so by transforming each element in the collection into one of these, using a Select() LINQ clause.

Using the accepted answer I put together the following code to json-serialize my failed constraints (using Json.NET):
TestContext.AddFormatter(obj =>
{
if (obj == null)
return x => "";
return x => JsonConvert.SerializeObject(x);
});

Related

Moq: Using the CallBase() for a method with parameters and a return value to perfrom the original behavior of the method

I wanted one method in mocked object to perfrom its original behavior and return a value by that behavior. But I could not make it.
The below is a sample code.
public interface IMyTest {
public StringBuilder GetBuilder(string initial);
}
public class MyTest : IMyTest {
public StringBuilder GetBuilder(string initial) {
return new StringBuilder(initial + initial);
}
}
[TestFixture]
public class MyTestTest {
[Test]
public void GetBuilderTest() {
Mock<IMyTest> obj = new() {
CallBase = true
};
obj.Setup(x => x.GetBuilder(It.IsAny<string>())).CallBase();
var a = obj.Object.GetBuilder("ABC");
TestContext.WriteLine(a.ToString());
}
}
So I have created a mock object of IMyTest, and wanted let the GetBuilder() method to do the actual original behavior of doubling the input string.
I thought the CallBase() is for such a purpose, but it raises an error like:
This is a DynamicProxy2 error: The interceptor attempted to 'Proceed' for method 'System.Text.StringBuilder GetBuilder(System.String)' which has no target. When calling method without target there is no implementation to 'proceed' to and it is the responsibility of the interceptor to mimic the implementation (set return value, out arguments etc)
Because I am still new to Moq, I might be misunderstanding, but could not find an answer by googling. So if you could kindly help on my question.
Of course, it can use the Return() with the same new StringBuilder(initial + initial) in it, but please think that method is doing very complex work inside of it actually that I do not want to mimic it manually.

How to Make Collection Stop Calling Equals when Performing Collection.Remove

I have a Class Test which has a overriden method for "Equals" method and then I have a TestCollection class which is implemented using ICollection<Test> & IEnumerable<Test> in the Collection I have implemented Remove method which just removes the item from the current TestCollection object.
Whenever I class remove method for the TestCollection object, this internally calls "Equals" method which is overridden at Test class.
For one of my scenario, I do not want this Equals to be called, what are the other ways where I can remove the item from my collection without calling Equals
Below is the sample code for better understanding.
Test Class
public class Test
{
public int Id { get; set; }
private Collection<Test> _entities = new Collection<Test>();
public bool Remove(Test item)
{
return this._entities.Remove(item);
}
public override bool Equals(object obj)
{
Console.WriteLine("Equals inside Test Object");
return true;
}
}
TestCollection class
public class TestCollection : ICollection<Test>, IEnumerable<Test>
{
public TestCollection() : base() { }
private Collection<Test> _entities = new Collection<Test>();
public TestCollection(IList<Test> entityList)
{
this._entities = new Collection<Test>(entityList);
}
public bool Remove(Test item)
{
return this._entities.Remove(item);
}
public override bool Equals(object obj)
{
Console.WriteLine("Equals inside Test Collection Object");
return true;
}
}
I think you are missing the point here. Equals method is implementing the arithmetic relation of equivalence, like having attributes of being reflexive, symmetric and transitive. There are no two distinct ways to say that two objects are equal, you see?
Solution for you is to remove implementation of the Equals method. This method is intended to be overridden if and only if there is exactly one definition of equivalence for a class - like integer equality - there is exactly one way to test whether two integers are equal.
Also, that is the reason why Remove method does not accept an additional parameter such as an IComparer or IEqualityComparer - that wouldn't make sense.
On a related note: Entities should never override Equals. There is no equality relation (in mathematical terms) defined for objects that can change their state over time, and entity is defined as an object with lifetime. The trouble there is that you can pick two versions of the same entity and ask whether they are equal. Well, they are both equal (that is the same entity) and not equal (those are two versions of it). Therefore, Equals method is not the way to check equality of entities.
The short answer is that you cannot.
The way that an item is removed from a list is done by doing an equality check for the item in question on each of the entries in the list.
There may be some way to do it, however, but I doubt it's a good practice, or even desirable code.
You could wrap the list into another list that uses a custom IEqualityComparer implementation. Allow that comparer to have two different modes (pass through to object.Equals, or don't) and switch them before remove (and switch back afterwards).
You could find the index of the item you want to remove (not use its Equal) and call RemoveAt

NUnit comparing two lists

OK so I'm fairly new to unit testing and everything is going well until now.
I'm simplifying my problem here, but basically I have the following:
[Test]
public void ListTest()
{
var expected = new List<MyClass>();
expected.Add(new MyOtherClass());
var actual = new List<MyClass>();
actual.Add(new MyOtherClass());
Assert.AreEqual(expected,actual);
//CollectionAssert.AreEqual(expected,actual);
}
But the test is failing, shouldn't the test pass? what am I missing?
If you're comparing two lists, you should use test using collection constraints.
Assert.That(actual, Is.EquivalentTo(expected));
Also, in your classes, you will need to override the Equals method, otherwise like gleng stated, the items in the list are still going to be compared based on reference.
Simple override example:
public class Example
{
public int ID { get; set; }
public override bool Equals(object obj)
{
return this.ID == (obj as Example).ID;
}
}
A very simple way to get this test to work is to only create the MyOtherClass instance once. That way, when comparing the item in the two lists they will be "equal" (because they reference the same object). If you do this, CollectionAssert will work just fine.
[Test]
public void ListTest()
{
var thing = new MyOtherClass();
var expected = new List<MyClass>();
expected.Add(thing);
var actual = new List<MyClass>();
actual.Add(thing);
CollectionAssert.AreEqual(expected,actual);
}
If you don't this though, you'll need to implement IEquatable<MyOtherClass> in MyOtherClass or override Equals to define what makes two instances of that class the "same".
Try to be a bit more specific about what you are trying to achieve. Explicitly telling that you want to compare entire sequence will solve the problem. I personally wouldn't rely on NUnit fancy features for determining what you meant by says AreEqual. E.g.
Assert.IsTrue(actual.SequenceEqual(expected));
I convert my comment to answer on request.
Well, this fails because AreEqual uses reference comparison. In order to make it work you need value comparison(your own custom comparison).
You can pretty much do that by implementing IEquatable interface. and keep in mind when you're implementing this interface you must override Object.Equals and Object.GetHashCode as well to get consistent results.
.Net framework supports doing this without implementing IEquatable you need IEqualityComparer that should do the trick, but nunit should have a method which takes this as a overload. Am not certain about "nunit" though.
From Nunit documentation:
Starting with version 2.2, special provision is also made for comparing single-dimensioned arrays. Two arrays will be treated as equal by Assert.AreEqual if they are the same length and each of the corresponding elements is equal. Note: Multi-dimensioned arrays, nested arrays (arrays of arrays) and other collection types such as ArrayList are not currently supported.
You have a list of objects ... so it's not the same as comparing 2 ints.
What you should do is probably compare all the objects inside the list ... (Try converting your list to an array ... might actually work :) )
As I said (and most others as well), you'll probably need to override Equals. Here's MSDN page about how to do it (Covers Equals, == operator, and GetHashCode).
Similar with more info :
[compare-equality-between-two-objects-in-nunit]
(Compare equality between two objects in NUnit)
If you can't modify a class then this example can be helpful:
[Test]
public void Arrays_Should_Be_Equal()
{
MyClass[] array1 = GetTestArrayOfSize(10);
MyClass[] array2 = GetTestArrayOfSize(10);
// DOESN'T PASS
// Assert.That(array1, Is.EquivalentTo(array2));
Func<MyClass, object> selector = i => new { i.Property1, i.Property2 };
Assert.That(array1.Select(selector), Is.EquivalentTo(array2.Select(selector)));
}
private MyClass[] GetTestArrayOfSize(int count)
{
return Enumerable.Range(1, count)
.Select(i => new MyClass { Property1 = "Property1" + i, Property2 = "Property2" + i }).ToArray();
}
Option 1: AreEquivalent
CollectionAssert.AreEquivalent(expectedList, actualList);
Option 2: IEqualityComparer - for custom equality comparisons
Assert.That(expectedList, Is.EqualTo(actualList).Using(new IEqualityComparerImplementation()));
private class IEqualityComparerImplementation: IEqualityComparer<T>
{
public bool Equals(GeometricPlane plane1, GeometricPlane plane2)
{
// obviously add in your own implementation
throw new NotImplementedException();
}
public int GetHashCode(GeometricPlane obj)
{
throw new NotImplementedException();
}
}

Method overloads object and unspecified type

I have the following method with an overload:
public string GetName(object obj)
{
return obj.ToString();
}
public string GetName(CustomClass cc)
{
return cc.Name + " - " + cc.Description;
}
Now if I call the method with an untyped IEnumerable wich holds CustomClass the GetName(object obj) gets called, to fix this I have modified the method like this:
public string GetName(object obj)
{
if (obj is CustomClass)
return GetName(obj as CustomClass);
return obj.ToString();
}
I think its rather annoying to write 20 IF statements and catch all the other possibilities, is there an easier way to call the correct overload with an untyped IEnumerable enumeration?
Here is the code that calls the GetName(object obj):
IEnumerable rawData = GetData(); //DataBase method that fetches a CustomClass
foreach (var rawDataItem in rawData)
{
Debug.Print(GetName(rawDataItem)); //calls the GetName(object obj) overload
}
Pls dont tell me to override ToString from my CustomClass, help me fix this method calling problem.
Well, you could use dynamic typing. That will basically defer overload resolution until execution time:
foreach (dynamic rawDataItem in rawData)
{
Debug.Print(GetName(rawDataItem));
}
Note that there's potentially a performance cost here - it may well be minimal and insignificant, but it's worth being aware of.
EDIT: To handle the recursion side of things, you'd probably want two different names, e.g. GetName and GetNameImpl where GetName delegates to GetNameImpl which is what all the useful overloads are called. So you'd have:
// Note that dynamic as a parameter type is equivalent to object for callers.
// The dynamic part is only relevant within the method.
public string GetName(dynamic obj)
{
return GetNameImpl(obj);
}
// Fallback when no other overloads match
private string GetNameImpl(object obj)
{
...
}
private string GetNameImpl(IEnumerable obj)
{
// Maybe build up the name by calling GetName on each element?
}
Note that there's a potential problem with this: if you have two overloads for different interfaces and one type implements both interfaces (but there isn't a specific overload for that type itself) then you'll get an exception at execution time.
If you want callers to be able to call the overloads directly, you could just rename the dynamic one to GetNameDynamic and the others to GetName for example (and make them public).
I rarely find that dynamic is a good solution, but it would avoid the code duplication. I would try to step back and find a different design to be honest. You explicitly rejected it in the question, but polymorphism is the preferred way of handling this. You don't need to necessarily override ToString - you could make all of the custom types implement a particular interface, and use that where it's available, for example.
return GetName((dynamic)obj);
will postpone overload resolution till runtime.
Without dynamic typing, the classic OOP solution to supporting double dispatch (where the method called depends on both the concrete type of the object having the method and the concrete type of the passed object) is the visitor pattern.
Try this:
public string GetName(object obj)
{
if (!(obj is IEnumerable<object>))
return GetName(obj as CustomClass);
return obj.ToString();
}

Combination of Moq and Equals() crashing the MS Testing framework

I have what I think should be a very simple test case, but every time I run it QTAgent32 dies. Running the test case in Debug mode shows a System.StackOverflowException being thrown in 'Unknown Module'. I've narrowed it down to the most basic implementation that exhibits this behavior (.NET 4 and VS 2010 Ultimate):
[TestClass]
public class StackOverflow
{
[TestMethod]
public void CreateStackOverflow()
{
var mockMyType1 = new Mock<MyType>();
mockMyType1.Setup(m => m.Equals(mockMyType1.Object)).Returns(true);
var mockMyType2 = new Mock<MyType>();
// Real test is for a filtering routine and the Assert is using
// Contains(), but it uses Equals() internally so it has the same problem
Assert.IsTrue(mockMyType1.Object.Equals(mockMyType1.Object)); // returns true
Assert.IsFalse(mockMyType1.Object.Equals(mockMyType2.Object)); // explodes
}
}
public class MyType
{
public virtual bool IsActive { get; set; }
public override bool Equals(object obj)
{
return false; // Not the real implementation but irrelevant to this issue
}
}
I feel like I'm missing something important about closures or maybe Moq, but it seems like this should work. Things I have tried, attempting to understand the issue, but have only confused me more:
I tried replacing the Equals() setup with mockMyType.Setup(m => m.Equals(m)).Returns(true); but that causes Moq to throw an NotSupportedException
If I make CallBase true instead of setting up Equals(), everything works
Finally, if the MyType class doesn't override Equals(), everything works.
Can anyone point me in the direction of what might be happening? I'm completely at a loss.
Edit: I believe I have a couple of options for making this work (including Lanorkin's response below), but I'd really like to know why this is happening. Am I doing something wrong or is there a bug in Moq or Visual Studio that I should be submitting?
Update: I ended up going with a version of Denys solution below and filing a bug report to Moq. My setup now looks like:
mockMyType1.Setup(m => m.Equals(It.Is<MyType>(x => ReferenceEquals(x, mockMyType1.Object)))).Returns(true);
Yes, mocking Equals(object) make it fail (use Reflector/dotPeek to see more):
Good news - it's easy to workaround. Just add Equals overload to MyType class, thus mocking Equals(MyType) instead of Equals(object):
public virtual bool Equals(MyType obj)
{
return Equals((object)obj);
}
This question disturbs me since yesterday and finally I found the answer. You have to use a function in your setup method and it should assert against real equality of the mock objects. What I mean is ReferenceEquals. So I modified your GetMockMyTypes code. Sure it can't be used as a reference but intent is clear so far:
public static class MyTypeHelper
{
public static IList<MyType> GetMockMyTypes()
{
var myTypes = new List<MyType>();
var myMock1 = new Mock<MyType>().Object;
Mock.Get(myMock1)
.Setup(m => m.Equals(It.Is<MyType>(x => ReferenceEquals(x, myMock1))))
.Returns(true);
Mock.Get(myMock1).Setup(m => m.IsActive).Returns(false);
myTypes.Add(myMock1);
var myMock2 = new Mock<MyType>().Object;
Mock.Get(myMock2)
.Setup(m => m.Equals(It.Is<MyType>(x => ReferenceEquals(x, myMock2))))
.Returns(true);
Mock.Get(myMock2).Setup(m => m.IsActive).Returns(true);
myTypes.Add(myMock2);
return myTypes;
}
}
I think the issue is that you do:
mockMyType.Setup(m => m.Equals(mockMyType.Object)).Returns(true);
which only mocks against parameter of that same object. If you use any other parameter it will not get matched.
Please try to do this instead:
mockMyType.Setup(m => m.Equals(It.IsAny<MyType>())).Returns(true);
However, you should get a different exception about unexpected method call.

Categories