简体   繁体   中英

Calling Excluding method in extension method for FluentAssertions.Primitives.ObjectAssertions does not work, but calling it normally works

I have started using FluentAssertions library in my integration tests for the REST endpoints. The problem is I have to compare two entities, but excluding their _id properties. This property is being inherited from my IEntity interface.

public interface IEntity
{
    [BsonId]
    ObjectId _id { get; set; }
}

So for example Log class looks like this

[DataContract]
public class Log : IEntity
{
    [BsonId]
    public ObjectId _id { get; set; }

    public string Message { get; set; }
}

In the test I am comparing them like this and it works

retrieved.Should()
         .BeEquivalentTo(expected, options => options.Excluding(member => member._id));

But when I extract this functionality to extension method for reuse purposes, it does not work. It does not ignore the _id member.

public static class ObjectAssertionExtensions
{
    public static void BeEquivalentToExcludingId<TExpectation>(this ObjectAssertions objectAssertion, TExpectation expectation) where TExpectation : IEntity
    {
        objectAssertion.BeEquivalentTo(expectation, options => options.Excluding(member => member._id));
    }
}

When I change the generic extension method to a specific type Log , then it works like it should. I have prepared minimal project with example here . Is there a way how to get this working please and why does it not work properly? I will try to check the code of FluentAssertions in github repository. Thanks.

First of all, in ObjectAssertionsExtensions it makes sense to change

public static void BeEquivalentToExcludingId<TExpectation>(this ObjectAssertions objectAssertion,
    TExpectation expectation) where TExpectation : IEntity

to

public static void BeEquivalentToExcludingId(this ObjectAssertions objectAssertion,
    IEntity expectation)

I'd also put each assertion into separate test to localize the problem.

The thing happens because BeEquivalentToExcludingId expects IEntity with _id property only, but gets Log with extra Message property. That makes everything go wrong. If it doesn't harm your architecture just ammend IEntity with string Message property and it will fix the thing. So, the only change:

public interface IEntity
{
    [BsonId]
    ObjectId _id { get; set; }

    string Message { get; set; }
}

solves the problem.

Update:

Taking into account your comment, just set members to exclude to the same value, call BeEquivalentTo and set actual values back like this:

public static void BeEquivalentToExcludingId(this ObjectAssertions objectAssertion, IEntity expectation)
{
    var subj = (IEntity)objectAssertion.Subject;
    var subjId = subj._id;
    var expId = expectation._id;

    subj._id = ObjectId.Empty;
    expectation._id = ObjectId.Empty;

    objectAssertion.BeEquivalentTo(expectation);

    subj._id = subjId;
    expectation._id = expId;
}

It's hacky, but it works.

The problem is that Fluent Assertions fails to correlate _id of the generic type T to _id of the concrete type Log .

A similar issue was reported in #1077 and resolved with #1087 . As of writing we haven't released new version containing this fix.

Edit 2019-08-10:

Fluent Assertions 5.8.0 has been released with the fix.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM