question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

ShouldBeEquivalentTo with option RespectingRuntimeTypes does not respect runtime types

See original GitHub issue

This test should fail IMHO, but it doesn’t. Am I wrong, or is this a bug? Maybe I misunderstood RespectingRuntimeTypes.

using System.Collections.Generic;
using FluentAssertions;
using Xunit;

public class Container
{
	public Container(params IItem[] items) { this.Items = items; }
	public IReadOnlyCollection<IItem> Items { get; }
}

public interface IItem
{
}

public class A : IItem
{
	public A(string s) { this.S = s; }
	public string S { get; }
}

public class B : IItem
{
	public B(string s) { this.S = s; }
	public string S { get; }
}

public class Repro
{
	[Fact]
	public void DifferentRuntimeTypesShouldNotBeEquivalentWhenUsingRespectingRuntimeTypes()
	{
		var a = new Container(new A("A"));
		var b = new Container(new B("A"));

		// this should fail but succeeds
		a.Should().BeEquivalentTo(b, o => o.RespectingRuntimeTypes());
	}
}

Expected behavior:

The above test should fail because the elements in the lists of the containers have a different A vs. B and I specified to RespectRuntimeTypes.

Actual behavior:

The test succeeds and does not detect the difference.

Versions

<PropertyGroup>
    <TargetFramework>netcoreapp2.1</TargetFramework>
  </PropertyGroup>

  <ItemGroup>
    <PackageReference Include="FluentAssertions" Version="5.5.3" />
    <PackageReference Include="xunit.core" Version="2.4.1" />
    <PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.7.2" />
    <PackageReference Include="xunit.runner.visualstudio" Version="2.4.1" />
    <Reference Include="Microsoft.CSharp" />
  </ItemGroup>

Issue Analytics

  • State:closed
  • Created 5 years ago
  • Reactions:2
  • Comments:11 (11 by maintainers)

github_iconTop GitHub Comments

4reactions
ursenzlercommented, Nov 12, 2020

Got it working for my scenarios:

	public class MatchTypeEquivalencyStep : IEquivalencyStep
	{
		public bool CanHandle(
			IEquivalencyValidationContext context,
			IEquivalencyAssertionOptions config)
		{
			Type subjectType = config.GetExpectationType(context);

			return !IsCollection(subjectType) && !IsAnonymousType(subjectType);
		}

		public bool Handle(
			IEquivalencyValidationContext context,
			IEquivalencyValidator parent,
			IEquivalencyAssertionOptions config)
		{
			if (context.Subject != null && context.Expectation != null)
			{
				context.Subject.GetType().Should().Be(context.Expectation.GetType());
			}

			return false;
		}

		private static bool IsCollection(
			Type type)
		{
			return !typeof(string).IsAssignableFrom(type) && typeof(IEnumerable).IsAssignableFrom(type);
		}

		private static bool IsAnonymousType(
			Type type)
		{
			bool hasCompilerGeneratedAttribute = type.GetCustomAttributes(typeof(CompilerGeneratedAttribute), false).Any();
			bool nameContainsAnonymousType = type.FullName.Contains("AnonymousType");
			bool isAnonymousType = hasCompilerGeneratedAttribute && nameContainsAnonymousType;

			return isAnonymousType;
		}
	}
}

I really like the extensibility provided by FluentAssertions 😃

1reaction
ursenzlercommented, Nov 12, 2020

This is a great idea.

Unfortunately, I struggle to implement my own EquivalencyStep.

I have this:

public class MatchTypeEquivalencyStep : IEquivalencyStep
{
	public bool CanHandle(
		IEquivalencyValidationContext context,
		IEquivalencyAssertionOptions config)
	{
		return true; // what to write here?
	}

	public bool Handle(
		IEquivalencyValidationContext context,
		IEquivalencyValidator parent,
		IEquivalencyAssertionOptions config)
	{
		context.Subject.GetType().Should().Be(context.Expectation.GetType());

		return false;
	}

	private static bool IsCollection(Type type)
	{
		return !typeof(string).IsAssignableFrom(type) && typeof(IEnumerable).IsAssignableFrom(type);
	}
}

But, whatever I write in the CanHandle method, the result is a NullReferenceException somewhere in FluentAssertions.

It should not handle any kind of collections (that’s why I copied the IsCollection method from FluentAssertions).

Do you have a tip for me?

Additionally, I’m not sure whether the Handle method is correct. I’m a bit rusty with these RuntimeTypes.

Read more comments on GitHub >

github_iconTop Results From Across the Web

FluentAssertions Should().BeEquivalentTo() fails with Lists ...
The test currently fails. I'm suspecting it has something to do with Should().BeEquivalentTo not being fit to compare run-time specified types.
Read more >
Object graph comparison
BeEquivalentTo(order, options => options. RespectingDeclaredTypes()); One exception to this rule is when the declared type is object . Since object doesn't ...
Read more >
Excluding certain properties when asserting objects with ...
It's very common that we assert if two objects are equivalent in unit tests. ... ShouldBeEquivalentTo(expected, options => { options.
Read more >
Fluent Assertions just a got a little bit better
When an object implements IDictionary<T,K> more than once, ShouldBeEquivalentTo will fail rather than pick a random implementation. Likewise, if ...
Read more >
Fluent Assertions - RSSing.com
Fluent Assertions supports MSTest, NUnit, XUnit, MSpec, MBUnit and the Gallio Framework. You can simply add a reference to the corresponding test framework ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found