In an earlier question I asked about Autofixture's CreateProxy method, a potential bug was identified.
I don't think this failing test is as a result of that, but rather my continued confusion about how the Likeness.Without(...).CreateProxy() syntax works. Consider the following failing test in which I make the original test ever so slightly more complex by creating a new instance of the object, considering its creation to be the SUT:
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass,
Strings = template.Brass};
// intent -> specify that .Brass should not be considered in comparison
var likeness = template.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // Ignore .Brass property
// per [https://stackoverflow.com/a/15476108/533958] explicity assign
// properties to likeness
likeness.Strings = template.Strings;
likeness.Brass = "foo"; // should be ignored
// assert: intent -> check equality between created Band & template Band
// to include all members not excluded in likeness definition
likeness.Should().Be(createdBand); // Fails
likeness.ShouldBeEquivalentTo(createdBand); // Fails
Assert.True(likeness.Equals(createdBand)); // Fails
}
Here's the Band:
public class Band
{
public string Strings { get; set; }
public string Brass { get; set; }
}
My earlier question wasn't sufficiently complex to help me understand what the Source
of the Likeness
should be in general.
Should the source be the output of the SUT, in which case it would be compared to the template instance created by AutoFixture?
Or should the source be the template instance created by AutoFixture, in which case it would be compared to the output of the SUT?
EDIT: Corrected an error in the test
I realized that I had incorrectly assigned the template.Brass
property to both the Brass
and the Strings
property of the new Band
instance. The updated test reflects the correction with var createdBand = new Band {Brass = template.Brass, Strings = template.Strings}
and all six assertions pass now.
[Fact]
public void Equality_Behaves_As_Expected()
{
// arrange: intent -> use the fixture-created Band as Object Mother
var template = new Fixture().Create<Band>();
// act: intent -> instantiated Band *is* the SUT
var createdBand = new Band {Brass = template.Brass, Strings = template.Strings};
// likeness of created
var createdLikeness = createdBand.AsSource().OfLikeness<Band>().
Without(x => x.Brass).CreateProxy(); // .Brass should not be considered in comparison
// https://stackoverflow.com/a/15476108/533958 (explicity assign properties to likeness)
createdLikeness.Strings = createdBand.Strings;
createdLikeness.Brass = "foo"; // should be ignored
// likeness of template
var templateLikeness = template.AsSource().OfLikeness<Band>()
.Without(x => x.Brass)
.CreateProxy();
templateLikeness.Strings = template.Strings;
templateLikeness.Brass = "foo";
// assert: intent -> compare created Band to template Band
createdLikeness.Should().Be(template);
createdLikeness.ShouldBeEquivalentTo(template);
Assert.True(createdLikeness.Equals(template));
templateLikeness.Should().Be(createdBand);
templateLikeness.ShouldBeEquivalentTo(createdBand);
Assert.True(templateLikeness.Equals(createdBand));
}
What you mean is:
likeness.Should().BeAssignableTo<Band>(); // Returns true.
In the example provided, the proxy generated from Likeness
is a type deriving from Band
, overriding Equals
using the Semantic Comparison algorithm.
Using Reflection that is:
createdBand.GetType().IsAssignableFrom(likeness.GetType()) // Returns true.
Update:
The createBand and template instances are not affected by the CreateProxy
method. Why they should?
With Likeness CreateProxy
you basically create a Custom Equality Assertion that allows you to do:
Assert.True(likeness.Equals(createdBand)); // Passed.
Without it, the original Equality Assertion would fail:
Assert.True(template.Equals(createdBand)); // Failed.
However, the following will also fail:
Assert.True(likeness.Equals(template));
It fails because the Strings
value is the one from the createdBand instance.
This behavior is expected, and you can verify it using Likeness
directly:
createdBand.AsSource().OfLikeness<Band>()
.Without(x => x.Brass).ShouldEqual(template);
Output:
The provided value `Band` did not match the expected value `Band`. The following members did not match:
- Strings.