-
Notifications
You must be signed in to change notification settings - Fork 732
BeEquivalentTo and NotBeEquivalentTo consistency #1036
Copy link
Copy link
Closed as not planned
Labels
Description
Description
I may have found some weird cases when using the BeEquivalentTo and NotBeEquivalentTo functions. To put it short:
- Using compile time type to check equivalence seems a little bit weird.
- BeEquivalentTo is not mutually exclusive with NotBeEquivalentTo on IEnumerable.
- NotBeEquivalentTo is not implemented on an object where BeEquivalentTo is.
- BeEquivalentTo on an object is not commutative.
I like to hear some other views and opinions on this.
Complete minimal example reproducing the issue
The test cases 1 to 6 represent my line of thought.
using System.Collections.Generic;
using FluentAssertions;
using FluentAssertions.Execution;
using NUnit.Framework;
namespace FluentAssertionTests
{
public abstract class Car
{
protected Car(string licensePlate)
{
LicensePlate = licensePlate;
}
public string LicensePlate { get; }
}
public class Peugeot : Car
{
public Peugeot(string licensePlate, string peugeotNumber)
: base(licensePlate)
{
PeugeotNumber = peugeotNumber;
}
public string PeugeotNumber { get; }
}
[TestFixture]
public class Tests
{
private Car _expected;
private IEnumerable<Car> _expectedIEnumerable;
private Car _actual;
private IEnumerable<Car> _actualIEnumerable;
/// <summary>
/// I expect all the statements in this scope to fail, but they all succeed.
/// </summary>
[Test]
public void TestCase1()
{
using(new AssertionScope())
{
_expectedIEnumerable.Should().BeEquivalentTo(_actualIEnumerable);
new[] { _expected }.Should().BeEquivalentTo(_actualIEnumerable);
_expected.Should().BeEquivalentTo(_actual);
}
}
/// <summary>
/// All the statements fail, as I expect.
/// </summary>
[Test]
public void TestCase2()
{
using(new AssertionScope())
{
new[] { _expected }.Should().BeEquivalentTo(new[] { _actual });
_expectedIEnumerable.Should().BeEquivalentTo(new[] { _actual });
}
}
/// <summary>
/// In order to let TestCase1 fail, the RespectingRuntimeTypes option has to be enabled. Can this be the default instead
/// of compile time type?
/// </summary>
[Test]
public void TestCase3()
{
using(new AssertionScope())
{
_expectedIEnumerable.Should().BeEquivalentTo(_actualIEnumerable, o => o.RespectingRuntimeTypes());
new[] { _expected }.Should().BeEquivalentTo(_actualIEnumerable, o => o.RespectingRuntimeTypes());
_expected.Should().BeEquivalentTo(_actual, o => o.RespectingRuntimeTypes());
}
}
/// <summary>
/// I expect BeEquivalentTo and NotBeEquivalentTo to be mutually exclusive. But this test succeeds.
/// </summary>
[Test]
public void TestCase4()
{
using(new AssertionScope())
{
_expectedIEnumerable.Should().BeEquivalentTo(_actualIEnumerable);
_expectedIEnumerable.Should().NotBeEquivalentTo(_actualIEnumerable);
}
}
/// <summary>
/// There is no ObjectAssertions NotBeEquivalentTo method. Can this be added?
/// </summary>
[Test]
public void TestCase5()
{
using(new AssertionScope())
{
_expected.Should().BeEquivalentTo(_actual);
//_expected.Should().NotBeEquivalentTo(_actual);
}
}
/// <summary>
/// Here I expect both statements to fail, only the second one fails.
/// </summary>
[Test]
public void TestCase6()
{
using(new AssertionScope())
{
new Peugeot("AA-AA-AA", "123").Should().BeEquivalentTo(_actual);
_expected.Should().BeEquivalentTo(new Peugeot("AA-AA-AA", "456"));
}
}
[OneTimeSetUp]
public void OneTimeSetUp()
{
_expected = new Peugeot("AA-AA-AA", "123");
_expectedIEnumerable = new[] { _expected };
_actual = new Peugeot("AA-AA-AA", "456");
_actualIEnumerable = new[] { _actual };
}
}
}Expected behavior:
- Using runtime type to check equivalence as default. This has the most information value. Create the inverse option to use the compile time type when needed. Potentially a lot of tests will break.
- Make BeEquivalentTo mutually exclusive with NotBeEquivalentTo given the same parameters. Either things are equivalent, or they are not. Exclusive or. Law of excluded middle.
- Because BeEquivalentTo is implemented on objects, so will NotBeEquivalentTo.
- BeEquivalentTo is commutative. So left.BeEquivalentTo(right) will yield the same result as right.BeEquivalentTo (left). The same applies to NotBeEquivalentTo.
Actual behavior:
See the 6 test cases. Please read them top down and the actual behavior will be clear.
Versions
Using version 5.6.0 of Fluent Assertions and .NETCoreApp 2.2.
Reactions are currently unavailable