Testing Optional equivalence with FluentAssertions - c#

I'm using a library called Optional (https://github.com/nlkl/Optional) that allows the "maybe" abstraction that is common to functional languages.
The library is awesome, but I'm facing a problem regarding testing: I can't test correctly whether 2 optional instances are equivalent or not.
To test for equivalence I'm using Fluent Assertions. However, I'm not getting the desired results.
I will illustrate the problem with code:
#load "xunit"
[Fact]
void TestOptional()
{
var a = new[] { 1, 2, 3 }.Some();
var b = new[] { 1, 2, 3 }.Some();
a.Should().BeEquivalentTo(b);
}
This test fails, as I show in the screenshot (I'm using LINQPad, for convenience)
As you see, this isn't what one expects.
How do I tell Fluent Assertions to check the equivalence correctly using the Option type?

UPDATE
I opened an issue on Github regarding your problem and yesterday a pull request was merged, so the next (pre-)release should enable you to solve your problem elegantly:
The new overloads allows you to use an open generic type.
If both an open and closed type are specified, the closed type takes precedence.
SelfReferenceEquivalencyAssertionOptions adds the following methods:
public TSelf ComparingByMembers(System.Type type) { }
public TSelf ComparingByValue(System.Type type) { }
Here's the unit test that was added to Fluent Assertions showing how it works:
[Fact]
public void When_comparing_an_open_type_by_members_it_should_succeed()
{
// Arrange
var subject = new Option<int[]>(new[] { 1, 3, 2 });
var expected = new Option<int[]>(new[] { 1, 2, 3 });
// Act
Action act = () => subject.Should().BeEquivalentTo(expected, opt => opt
.ComparingByMembers(typeof(Option<>)));
// Assert
act.Should().NotThrow();
}
Fluent Assertions - Object Graph Comparison says:
Value Types
To determine whether Fluent Assertions should recurs into an object’s
properties or fields, it needs to understand what types have value
semantics and what types should be treated as reference types. The
default behavior is to treat every type that overrides Object.Equals
as an object that was designed to have value semantics. Unfortunately,
anonymous types and tuples also override this method, but because we
tend to use them quite often in equivalency comparison, we always
compare them by their properties.
You can easily override this by using the ComparingByValue<T> or
ComparingByMembers<T> options for individual assertions
Option<T> is a struct and overrides Equals, so Fluent Assertions compares a and b with value semantics.
Option<T> implements Equals like this:
public bool Equals(Option<T> other)
{
if (!this.hasValue && !other.hasValue)
return true;
return this.hasValue
&& other.hasValue
&& EqualityComparer<T>.Default.Equals(this.value, other.value);
}
Thus int[] is compared by reference and your test fails.
You can override this behavior for each test individually, like Guro Stron said:
a.Should().BeEquivalentTo(b, opt => opt.ComparingByMembers<Option<int[]>>());
Or globally via static AssertionOptions class:
AssertionOptions.AssertEquivalencyUsing(options =>
options.ComparingByMembers<Option<int[]>>());
edit:
For your case Fluent Assertions would need an AssertEquivalencyUsing override that supports unbound generic types:
AssertionOptions.AssertEquivalencyUsing(options =>
options.ComparingByMembers(typeof(Option<>)));
No such override exists, unfortunately.
Another solution a came up with would be an extension method. Here a very simplistic implementation:
public static class FluentAssertionsExtensions
{
public static void BeEquivalentByMembers<TExpectation>(
this ComparableTypeAssertions<TExpectation> actual,
TExpectation expectation)
{
actual.BeEquivalentTo(
expectation,
options => options.ComparingByMembers<TExpectation>());
}
}

Related

Mocked method returns null when using anonymous types

I have this code:
using NSubstitute;
using NUnit.Framework;
using System;
using System.Linq.Expressions;
namespace MyTests
{
public interface ICompanyBL
{
T GetCompany<T>(Expression<Func<Company, T>> selector);
}
public partial class Company
{
public int RegionID { get; set; }
}
public class Tests
{
[Test]
public void Test()
{
var companyBL = Substitute.For<ICompanyBL>();
//Doesn't work
companyBL.GetCompany(c => new { c.RegionID }).Returns(new
{
RegionID = 4,
});
//Results in null:
var company = companyBL.GetCompany(c => new { c.RegionID });
//This works:
//companyBL.GetCompany(Arg.Any<Expression<Func<Company, Company>>>()).Returns(new Company
//{
// RegionID = 4,
//});
//Results in non null:
//var company = companyBL.GetCompany(c => new Company { RegionID = c.RegionID });
}
}
}
When I use this code, the company var is null.
However, the commented out code works fine and results in a non null value.
Why does it not work with the anonymous type?
Is there some way to get this to work with anonymous types?
NSubstitute version = 1.10.0.0.
.NET Framework version = 4.5.2.
Because by default configured value will be returned only when arguments passed to the method are equal to the arguments configured with the mock.
Expression<Func<Company, T>> is a reference type and will be equal to another instance when both instances reference same object.
In your case configured mock and actual code receive different instances of two different objects.
You can use working approach suggested by David and Dave.
Which solving compilation error when NuSubstitute can not figure out which type is used for a selector.
Such approaches will work, but for failing tests provides little information about actual reason (in case wrong selector is given to the method)
Sometimes implement your own mock will have some benefits
public class FakeBusiness : ICompanyBL
{
private MyCompany _company;
public FakeBusiness For(MyCompany company)
{
_company = company;
return this;
}
public T GetCompany<T>(Expression<Func<MyCompany, T>> selector)
{
return selector.Compile().Invoke(_company);
}
}
Usage
[Fact]
public void TestObjectSelector()
{
var company = new MyCompany { RegionId = 1, Name = "One" };
var fakeBl = new FakeBusiness().For(company); // Configure mock
var actual = fakeBl.GetCompany(c => new { c.Name }); // Wrong selector
actual.Should().BeEquivalentTo(new { RegionId = 1 }); //Fail
}
And failed message now is more descriptive:
Expectation has member RegionId that the other object does not have.
Passing test
[Fact]
public void TestObjectSelector()
{
var company = new MyCompany {RegionId = 1, Name = "One"};
var fakeBl = new FakeBusiness().For(company); // Configure mock
var actual = fakeBl.GetCompany(c => new { c.RegionId });
actual.Should().BeEquivalentTo(new { RegionId = 1 }); // Ok
}
#Fabio's explanation is correct:
Expression<Func<Company, T>> is a reference type and will be equal to another instance when both instances reference same object.
In your case configured mock and actual code receive different instances of two different objects.
You can read more about this in related questions such as NSubstitute - Testing for a specific linq expression.
Solving using a hand-coded substitute
Please see #Fabio's answer for a good explanation of how to hand-code a substitute to solve the problem and provide useful assertion messages. For complex substitutions sometimes it is simplest and most reliable to skip a library and to generate the exact type you need for your test.
Incomplete work-around with NSubstitute
This case in particular is more difficult than the standard expression-testing case (using Arg.Any or Arg.Is) because we can't explicitly refer to the anonymous type. We could use ReturnsForAnyArgs, but we need to be clear about which generic method version we're calling (again, we can't explicitly refer to the anonymous type required for T).
One hacky way to work around this is to pass the expression as you were originally doing (which gives us the correct generic type), and use ReturnsForAnyArgs so the exact identity of that expression does not matter.
[Fact]
public void Test() {
var companyBL = Substitute.For<ICompanyBL>();
// Keep expression in `GetCompany` so it calls the correct generic overload.
// Use `ReturnsForAnyArgs` so the identity of that expression does not matter.
companyBL.GetCompany(c => new { c.RegionID }).ReturnsForAnyArgs(new {
RegionID = 4,
});
var company = companyBL.GetCompany(c => new { c.RegionID });
Assert.NotNull(company);
}
As noted in #Nkosi's comment, this has the drawback that it only does a minimal assertion on the type used for the selector expression. This would also pass in the test above:
var company = companyBL.GetCompany(c => new { RegionID = 123 });
As an aside, we do get some very basic checking of the expression, as the combination of generic type and anonymous types means that selecting the wrong field will not compile. For example, if Company has string Name property we will get a compile error:
companyBL.GetCompany(c => new { c.RegionID }).ReturnsForAnyArgs(new { RegionID = 4 });
var company= companyBL.GetCompany(c => new { c.Name });
Assert.Equal(4, company.RegionID); // <- compile error CS1061
/*
Error CS1061: '<anonymous type: string Name>' does not contain a definition
for 'RegionID' and no accessible extension method 'RegionID' accepting a first
argument of type '<anonymous type: string Name>' could be found (are you missing
a using directive or an assembly reference?) (CS1061)
*/
Assuming that the previous options may not be desirable, another approach may be available to you, if you have access to the (in this case) source for CompanyBL.
This alternative is to mark the methods needed to be mocked as virtual and have the mock inherit from the concrete class CompanyBL rather than implement the whole interface.
The reason you may want to do this is to make the mock less fragile .. ie when someone extends the ICompanyBL interface they will not need to add implementations to the mock.
While this is not an answer for specifically how to use NSubstitute I feel it is a worthwhile alternative. A variation may be to change CompanyBL to have protected virtual methods for functionality that needs to be replaced in the mock. Writing code that is more testable should be a concern which arguably merits these types of changes.
As Fabio and David Tchepak have already pointed out, my code wasn't working because it couldn't find a match for my method's argument because it was a different object to what was set up in the mock.
Here's another way to fix this:
[Test]
public void Test()
{
var companyBL = Substitute.For<ICompanyBL>();
Expression<Func<Company, object>> x = c => new { c.RegionID };
companyBL.GetCompany(x).Returns(new
{
RegionID = 4,
});
var company = companyBL.GetCompany(x);
}

What Invokes and distinguishes "It", "Because" and "Establish"

I've started using MSpec recently, breaking classes into, Establish, Because and, It.
Although I know how to use them, I'm not sure what goes into making them work.
I know they are delegates
Because of = () =>
{
};
But when looking at how delegates are defined:
public delegate void Print(int value);
It looks like Establish, Because and, It are defined as delegates that return nothing (void) and take no arguments.
Which makes sense, but how are Establish, Because and, It distinguished from each other. I.e. What stops using It instead of Establish working just the same. And how does one of them know to use the other? i.e. It uses Establish
Also they just get put in the class. What Invokes them?
public class foobar: setup
{
private static int engineId;
Because of = () =>
{
};
It should = () =>
{
};
}
See the above has the delegates initialized to these functions. But I don't know how they get called and why this isn't okay:
public class foobar: setup
{
private static int engineId;
It of = () =>
{
};
It should = () =>
{
};
}
Can anyone clarify this for me please?
Those delegates are of different types, even though they all have the same signature. So they are distinguished based on their type. For example suppose you have this class from example usage:
[Subject("Authentication")]
public class When_authenticating_a_user
{
Establish context = () =>
{
Subject = new SecurityService();
};
Cleanup after = () =>
{
Subject.Dispose();
};
static SecurityService Subject;
}
And now you want to imitate running that test. You use reflection to get all fields first, because both context and after are fields:
var fields = typeof(When_authenticating_a_user).GetFields(BindingFlags.Instance | BindingFlags.NonPublic);
Now you have bunch of fields, but which is which? You can distinguish them by field type. One is of type Establish and another is of type Cleanup (both are delegate types with the same signature):
var establish = fields.FirstOrDefault(c => c.FieldType == typeof(Establish));
var cleanup = fields.FirstOrDefault(c => c.FieldType == typeof(Cleanup));
And then you create an instance and execute them according to some logic:
var instance = Activator.CreateInstance(typeof(When_authenticating_a_user));
// get method
var establishMethod = (Establish)establish.GetValue(instance);
// execute
establishMethod();
Yes, they're delegates, as declared here:
They're all parameterless void delegates, which are distinguished from each other in terms of how they're used in the framework. A method that accepts an It won't accept an Establish for example, so that indicated what the intention of the method is. Different delegates really are different types, even if they have the same signature. (You can create one delegate to wrap an instance of a different delegate type with a compatible signature, but that's relatively rare.)
I'm not saying I particularly like the framework or the names chosen, but having different delegates which happen to have the same signature makes perfect sense in terms of expressing the different intended meanings for those delegates.

Override ToString in NUnit without access to source code

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);
});

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();
}
}

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