nunit: PropertyConstraint throws away the more helpful message in the base constraint result

Problem

PropertyConstraint keeps the base constraint description but throws away the actual comparison message and just prints the actual value.

Starting with a familiar example, Is.EquivalentTo:

var actual = new SomeClass { SomeProperty = { 2, 3, 5, 7 } };
Assert.That(actual.SomeProperty, Is.EquivalentTo(new List<int> { 2, 3, 5, 8 }));

Expected: equivalent to < 2, 3, 5, 8 > But was: < 2, 3, 5, 7 > Missing (1): < 8 > Extra (1): < 7 >

But as soon as you compose it with PropertyConstraint:

var actual = new SomeClass { SomeProperty = { 2, 3, 5, 7 } };
Assert.That(actual, Has.Property("SomeProperty").EquivalentTo(new List<int> { 2, 3, 5, 8 }));

Expected: equivalent to < 2, 3, 5, 8 > But was: < 2, 3, 5, 7 >

In that example, just printing the actual value is still pretty okay. But when the value is a complex object that doesn’t .ToString() to something you care about, you get something like this:

Expected: property SomeProperty [long description from custom constraint] But was: <Appearance>

Assert.That(new SomeClass(), Has.Property("SomeComplexThing")
    .SomeCustomConstraint(expectedComplexThing));

Proposal

Here you can see the constraint, which understands the semantics of the actual value, getting thrown away. Only the actual value and success bool are retained:

https://github.com/nunit/nunit/blob/bf8f2dc863036655dc37583dd5b7408b356b6026/src/NUnitFramework/framework/Constraints/PropertyConstraint.cs#L73-L74

Rather than the existing code below, I think we should have an internal-for-now ChainedConstraintResult class which delegates all its writing to the base constraint result:

internal class ChainedConstraintResult : ConstraintResult
{
    private readonly ConstraintResult _baseResult;

    public ChainedConstraintResult(IConstraint constraint, ConstraintResult baseResult) : base(constraint, baseResult.ActualValue, baseResult.Status)
    {
        _baseResult = baseResult;
    }

    public override void WriteActualValueTo(MessageWriter writer)
    {
        _baseResult.WriteActualValueTo(writer);
    }
}

PropertyConstraint would then do this:

var baseResult = BaseConstraint.ApplyTo(propValue);
return new ChainedConstraintResult(this, baseResult);

About this issue

  • Original URL
  • State: closed
  • Created 7 years ago
  • Comments: 20 (19 by maintainers)

Commits related to this issue

Most upvoted comments

@nisha-kaushik you are most welcome. I’ve assigned the issue to myself, just so nobody else takes it (but it can be that @jnm2 makes more sense). Do you need any help creating a fork, building etc.?

I’ll help out with this one. Been looking for a project I actually use to help out with and what better time than Hacktoberfest. 😃