28

Is it possible to assign a fixed value to a property on a child instance when building a parent with Autofixture? It will add default values to all the properties on the child instance like a charm, but I would like to override and assign a specific value to one of the properties on the child instance.

Given this parent/child relationship:

public class Person
{
    public string FirstName { get; set; }
    public string LastName { get; set; }

    public Address Address { get; set; }
}

public class Address
{
    public string Street { get; set; }
    public int Number { get; set; }
    public string City { get; set; }
    public string PostalCode { get; set; }
}

I would like to assign a specific value to the City property on the address instance. I was thinking in the lines of this test code:

var fixture = new Fixture();

var expectedCity = "foo";

var person = fixture
    .Build<Person>()
    .With(x => x.Address.City, expectedCity)
    .Create();

Assert.AreEqual(expectedCity, person.Address.City);

That is not possible. I guess, by the reflection exception

System.Reflection.TargetException : Object does not match target type.

...that Autofixture tries to assign the value to a City property on the Person instance instead of an Address instance.

Any suggestions?

And yes, I know that I could just add an extra step like the following:

var fixture = new Fixture();

var expectedCity = "foo";

// extra step begin
var address = fixture
    .Build<Address>()
    .With(x => x.City, expectedCity)
    .Create();
// extra step end

var person = fixture
    .Build<Person>()
    .With(x => x.Address, address)
    .Create();

Assert.AreEqual(expectedCity, person.Address.City);

...but was hoping for the first version or something similar (fewer steps, more terse).

Note: I'm using Autofixture v3.22.0

Jens Andresen
  • 283
  • 1
  • 3
  • 6

3 Answers3

27

For completeness, here's another way to do it:

fixture.Customize<Address>(c => 
    c.With(addr => addr.City, "foo"));

var person = fixture.Create<Person>();

This will customize the creation of all instances of Address

If you end up using this often enough, it may be worthwhile wrapping it inside an ICustomization:

public class AddressConventions : ICustomization
{
    public void Customize(IFixture fixture)
    {
        fixture.Customize<Address>(c => 
            c.With(addr => addr.City, "foo"));
    }
}

fixture.Customize(new AddressConventions());
dcastro
  • 66,540
  • 21
  • 145
  • 155
12

Not to be dismissive of the question, but the simplest solution might actually be this:

[Fact]
public void SimplestThingThatCouldPossiblyWork()
{
    var fixture = new Fixture();
    var expectedCity = "foo";
    var person = fixture.Create<Person>();
    person.Address.City = expectedCity;
    Assert.Equal(expectedCity, person.Address.City);
}

Assignment of explicit values to properties is something most languages already excel at (C# certainly does), so I don't think AutoFixture needs a complicated DSL to reproduce half of that functionality.

Mark Seemann
  • 225,310
  • 48
  • 427
  • 736
  • 1
    While it is obvious to most of us that assignment of explicit values to properties in C# is (almost) without effort, the original question was can I in a parent/child relationship assign a fixed value to a property of the child _with_ Autofixture. The reason for the question is merely on the aesthetics as I think that grouping the value assignments using .With(….) syntax would be “prettier” when having multiple assignments (as subjectively as that is). Aesthetics aside, your answer gets the job done. – Jens Andresen Jan 07 '15 at 13:54
  • You can fix a value by implementing a custom `ISpecimenBuilder`, but not (I think) with the fluent DSL, when it's a Train Wreck property. I did get the impression from the question that you were aiming for pretty, but if you want the convention-based approach, I'll be happy to share it. – Mark Seemann Jan 07 '15 at 14:00
  • No, but thanks anyway. The train wreck is parked at the outermost boundary of my application and simply models an incoming data structure, so I’ll live with a handful of test cases that look...well...less pretty ;-) – Jens Andresen Jan 07 '15 at 14:50
  • I came across this question as I have the same issue. In my opinion, one of the nice features of AF is the ability to use the fluent API. It surprises me that AF does not support this. Since I am able to write the code fluently, it should work. To me it is a case of "Least Astonishment". – Flodpanter Nov 29 '16 at 13:26
  • Sadly this is not an option for me. If you have validation inside your constructor, this won't work. – IamDOM Jun 15 '20 at 20:29
  • 3
    Public setters is not a thing in 2020 – Nick Dec 02 '20 at 15:04
-1

You can use a Do method on the builder:

var person = this.fixture
               .Build<Person>()
               .Do( x => x.Address.City = expectedCity )
               .Create();

You can also inject and freeze your instance to the fixture:

this.fixture.Inject( expectedCity );
sgnsajgon
  • 664
  • 2
  • 13
  • 56
  • Have you actually tried to run that code? It throws an NullReferenceException when I run it. – Jens Andresen Jan 07 '15 at 08:45
  • ...and Inject will set all the string properties to the value of expectedCity - not really what I want – Jens Andresen Jan 07 '15 at 08:52
  • Indeed, there is a NullReferenceException for the *Do* method, what IMO can be considered as bug, because this method comes from interface named *IPostprocessComposer*, so post-processing should be done after the object and it's dependencies are created. – sgnsajgon Jan 07 '15 at 08:57
  • The simplest solution is just the assign statement after object is created: *person.Address.City = expectedCity;* – sgnsajgon Jan 07 '15 at 09:01
  • Look like you are right and it is a bug. According to its designer blog (https://blog.ploeh.dk/2009/06/09/CallingMethodsWhileBuildingAnonymousVariablesWithAutoFixture/), "you can mix With and Do, and ObjectBuilder will preserve the ordering." – bkqc Nov 08 '19 at 22:44