Is there anyway to specify what gets appended to the {context}
key of the built in assertions or potentially get the value of that context?
Sample
E.g. I managed to append to custom Assertions using AssertionSope
keys to custom Execution.Assertions
as follows:
Sample Classes
public class Foo
{
public Bar Bar { get; } = new Bar();
}
public class Bar
{
public bool IsFull {get; set; }
}
Extension Classes
public static class Extensions
{
public static FooAssertions Should(this Foo foo) => new FooAssertions(foo);
public static BarAssertions Should(this Bar bar) => new BarAssertions(bar);
public class FooAssertions
{
public Foo Subject { get; }
public FooAssertions(Foo subject)
{
Subject = subject;
}
[CustomAssertion]
public void HaveFullBar(string because = null, params object[] becauseArgs)
{
using (var scope = new AssertionScope())
{
scope.AddReportable("SubPath", "." + nameof(Foo.Bar));
Subject.Bar.Should().BeFull(because, becauseArgs);
}
}
}
public class BarAssertions
{
public Bar Subject { get; }
public BarAssertions(Bar subject)
{
Subject = subject;
}
[CustomAssertion]
public void BeFull(string because = null, params object[] becauseArgs)
{
Execute.Assertion
.ForCondition(Subject.IsFull)
.BecauseOf(because, becauseArgs)
.FailWith("Expected {context}{SubPath}.IsFull to be {0}{reason} but found {1}", true, Subject.IsFull);
}
}
}
Test Method
[TestMethod]
public void CustomTest()
{
var foo = new Foo();
foo.Should().HaveFullBar();
}
Output
Output: Expected foo.Bar.IsFull to be True but found False
Question
How can I append to the build in {context}
so that I don't have to re-invent the wheel for every single assertion FluentAssertion already provides?
E.g. calling the standard BooleanAssertions.Should().BeTrue()
:
[CustomAssertion]
public void BeFull(string because = null, params object[] becauseArgs)
{
Subject.IsFull.Should().BeTrue();
}
but this loses the SubPath of .Bar.IsFull
and outputs:
Output: Expected foo to be true, but found False.
Attempts
Attempt One
Tried to set the "context" of inner assertion scopes to some value, but it loses the previous values!
[CustomAssertion]
public void HaveFullBar(string because = null, params object[] becauseArgs)
{
using (new AssertionScope(".Bar"))
{
Subject.Bar.Should().BeFull(because, becauseArgs);
}
}
[CustomAssertion]
public void BeFull(string because = null, params object[] becauseArgs)
{
using (new AssertionScope(".IsFull"))
{
Subject.IsFull.Should().BeTrue();
}
}
This just returns .IsFull
which is the most inner AssertionScope:
Expected .IsFull to be true, but found False.
Attempt Two
Tried to add "{context}" into the constructor of AssertionScope
[CustomAssertion]
public void HaveFullBar(string because = null, params object[] becauseArgs)
{
using (new AssertionScope("{context}.Bar"))
{
Subject.Bar.Should().BeFull(because, becauseArgs);
}
}
[CustomAssertion]
public void BeFull(string because = null, params object[] becauseArgs)
{
using (new AssertionScope("{context}.IsFull"))
{
Subject.IsFull.Should().BeTrue();
}
}
This just outputs the most inner {context}.IsFull
Expected {context}.IsFull to be true, but found False.
Attempt Three
[CustomAssertion]
public void HaveFullBar(string because = null, params object[] becauseArgs)
{
using (new AssertionScope(AssertionScope.Current.Context + ".Bar"))
{
Subject.Bar.Should().BeFull(because, becauseArgs);
}
}
[CustomAssertion]
public void BeFull(string because = null, params object[] becauseArgs)
{
using (var scope = new AssertionScope(AssertionScope.Current.Context + ".IsFull"))
{
Subject.IsFull.Should().BeTrue();
}
}
Still loses original context, as the first AssertionScope.Current.Context
is
null
;
Output:
Expected .Bar.IsFull to be true, but found False.