Filling sub properties

Aug 3, 2010 at 8:36 PM
Edited Aug 3, 2010 at 8:43 PM

Hi, I try to use AutoFixture to create an instance of a complex Type which looks something like this:

class ComplexParent 
{ 
   private readonly _complexChild = new ComplexChild(); 
   public ComplexChild { get { return _complexChild; } } 

   public string Bla { get; set; } 
   public int Blub { get; set; } 
} 

class ComplexChild 
{ 
   public string Foo { get; set; } 
   public int Bar { get; set; } 
}

While CreateAnonymous() fills Bla and Blub with random values, the properties of ComplexChild remain in their initial state. Am I missing something or is this by design?

Thanks for you help!

Sebastian

Coordinator
Aug 3, 2010 at 9:48 PM
Edited Aug 3, 2010 at 9:51 PM

Thanks for writing and thank you for using AutoFixture.

Quite surprisingly you've actually discovered a behavior I was not aware of. Is it by design? No, not really. Is it a bug? Perhaps, but I'm not quite sure about that either...

As AutoFixture behaves right now (and has always done), it automatically fills all writable properties of instances it creates itself. In this case, when you ask it to create a ComplexParent, it populates the writable properties before serving the instance. In other words, Bla and Blub are populated because they are writable.

However, the ComplexChild property is read-only, so AutoFixture never creates an instance of it - and since it doesn't create an instance, its properties are never populated.

Now, I realize that ComplexChild in itself has writable properties, so it's not unreasonable to expect its properties to be populated. However, that's not what AutoFixture currently does because the population ignores read-only properties, even when they are complex and have writable properties of their own.

You could certainly argue that this is not intuitive. I'm not going to argue back :)

However, one thing is intuition, another is what an API implies. In most cases, a read-only property strongly signals that the parent controls the property. This could be a signal to AutoFixture that it should keep off that property.

The reason I've never before discovered this behavior despite having used AutoFixture heavily for more than a year is that I rarely design my classes like that. While I often have complex read-only properties, they tend to be populated with appropriate data. Even if the complex type has writable properties, I make sure that they are always in a valid state. So even when AutoFixture haven't been filling properties like those, I've never discovered it because there would have been values none the less.

Now, a completely different situation arises if we change the ComplexChild property to be writable. In that case, AutoFixture will assign a new value to the property, and since it creates an instance of ComplexChild to do that, it also assigns auto-properties to it. That's one possible workaround.

Another possible workaround is to explicitly fill the properties afterwords, but this can quickly get clunky:

var result = fixture.Build<ComplexParent>()
    .Do(x => x.Child.Bar = fixture.CreateAnonymous<int>())
    .Do(x => x.Child.Foo = fixture.CreateAnonymous("Foo"))
    .CreateAnonymous();

I'm creating an issue from this question. While I don't think it's a good idea to change the current auto-property behavior (it would be a breaking change), it might be a good idea to add recursive auto-properties as an option. However, in any case I'll be postponing this past the AutoFixture 2.0, release as it's not entirely trivial to add this feature.

Please let me know if you have further questions on this or other issues.


Coordinator
Aug 3, 2010 at 9:53 PM
This discussion has been copied to a work item. Click here to go to the work item and continue the discussion.
Aug 4, 2010 at 6:42 AM
Edited Aug 6, 2010 at 1:10 PM

Thank you very much for your quick reply at dead of night!

I posted my comments to the work item.

Btw: I read your book about DI via MEAP. It's great! I'm very much looking forward to the chapter about the different DI containers!

Aug 6, 2010 at 1:10 PM

OK, I found some time for further investigation. I used a solution that allows you to [Dynamically Invoke Generic Methods] I found at CodePlex.

The following snippet is just a PoC not something anybody should use without refinement.

using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Ploeh.AutoFixture;

namespace AutoFixtureFill
{
[TestClass]
public class FillFixture
{
public FillFixture() { }

public TestContext TestContext { get; set; }

[TestMethod]
public void CanFillExistingObject()
{
var fixture = new Fixture();

ComplexParent parent = fixture.CreateAnonymous<ComplexParent>();

fixture.Fill(parent.Child);

Assert.AreNotEqual(0, parent.Child.Bar);
Assert.IsNotNull(parent.Child.Foo);
Assert.AreNotEqual(0, parent.Child.Bar2);
}
}

public static class FixtureExtensions
{
public static void Fill(this Fixture fixture, object toFill)
{
if (fixture == null) throw new ArgumentNullException("fixture");
if (toFill == null) throw new ArgumentNullException("toFill");

Type type = toFill.GetType();

//get all writable properties of the object you want to be filled
IEnumerable<PropertyInfo> properties = type.GetProperties(BindingFlags.Public | BindingFlags.Instance).Where(p => p.CanWrite);

foreach (var p in properties)
{
var invoker = DynamicMethods.GenericMethodInvokerMethod(
//type on which the generic method should be invoked
  typeof(Fixture),
//name of the method you want to invoke
"CreateAnonymous",
//type parameter for the generic method (i.e. type of the property you want to set)
new Type[] { p.PropertyType },
//types of the parameters of the generic method. used to identify the proper method overload
//don't use NULL if you want to call a method that does not take parameters if there are overloads of the
//method but use an empty array instead
new Type[0]);

//use Fixture.CreateAnonymous<T> to generate a value for the property
object value = invoker.Invoke(fixture, null);

//write property value
p.SetValue(toFill, value, null);
}
}
}

class ComplexParent
{
public string Blub { get; set; }
public int Bla { get; set; }

private readonly ComplexChild _child;

public ComplexChild Child
{
get { return _child; }
}

public ComplexParent()
{
_child = new ComplexChild();
}
}

class ComplexChild
{
public string Foo { get; set; }
public int Bar { get; set; }
public int Bar2 { get; set; }
}
}

HIH

Sebastian

Coordinator
Aug 9, 2010 at 12:58 PM

Thanks for sharing :)

If you are using AutoFixture 2.0 (just released in beta today), you can do this a bit simpler:

var result = fixture.CreateAnonymous<ComplexParent>();
new AutoPropertiesCommand().Execute(
    result.Child,
    new SpecimenContext(fixture.Compose()));
I think this pretty well illustrates the power of AutoFixture 2.0's new kernel. Obviously, you could choose to wrap the second line of code in an extension method to make it a bit simpler to use.

Aug 10, 2010 at 8:05 AM

Well that looks like a lot less effort from my end :-)

I'm still figuring out the subtleties of AutoFixture so forgive me if this is documented elsewhere:

Can I use the above command together with Customize() to define a custom build-up sequence for my objects?

Coordinator
Aug 10, 2010 at 9:40 AM

Certainly. You can do this:

fixture.Customize<ComplexParent>(c =>
    c.Do(x => 
        new AutoPropertiesCommand().Execute(
            x.Child,
            new SpecimenContext(fixture.Compose()))));
and don't worry: it wasn't documented anywhere ;)

Jul 20, 2012 at 1:28 AM

hi - this exactly solves my problem.

I'm using dapper to map values to internal fields, then exposing the values wrapped in another type as readonly properties - so I needed to be able to make autofixture write to these internal fields.  I've modified the AutoPropertiesCommand to work on internal fields and the above idea totally works.

question - how do I make autofixture apply this customization to more than one type?  I've got a bunch of types I want to apply this to - is there a way to just apply this AutoPropertiesCommand to all objects populated through autofixture?

thanks

justin

Jul 20, 2012 at 1:59 AM

one other related question - I've now got a fixture customization which works fine.  

    fixture.Customize<MyType>(c => c.Do(x => new AutofixtureWriteInternalPropertiesCommand().Execute(x,new SpecimenContext(fixture.Compose()))));

but I've found that when I invoke a custom build on that type my fixture customization isn't invoked.

                    IList<MyType> blah = fixture
                        .Build<MyType>()
                        .With(m => m.MyProperty,explicitValue)
                        .CreateMany().ToList();

this is unexpected to me - how can I get the Command (defined in the fixture customization) to execute even when invoking a custom builder on my type?

thanks

Jul 20, 2012 at 9:22 AM

Hi Justin.

The Customize Registers a new building strategy. To just perform post processing, you need a different approach, which involves implementing ISpecimenBuilderTransformation as done in:

https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/DisposableTrackingCustomization.cs

https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/Kernel/DisposableTrackingBehavior.cs

https://github.com/AutoFixture/AutoFixture/blob/master/Src/AutoFixture/Kernel/DisposableTracker.cs

(I'll be building a LambdaPostProcessingBehavior based on DisposableTrackingBehavior soon and will paste it here when I do)

@Mark Seemann: Unless there's something neat built into the fluent api that I should be aware of or should I build an extension method as I allude to above?

Jul 20, 2012 at 4:12 PM

I implemented it: https://gist.github.com/3151233

Usage example there

Jul 24, 2012 at 12:32 AM

that's great - thanks very much for your response.  appreciate it. :)

Coordinator
Jul 25, 2012 at 11:15 AM

I'm a bit late to the game here, but these links might throw more light on the issues discussed here:

http://autofixture.codeplex.com/discussions/263060/

http://stackoverflow.com/questions/10032535/can-autofixture-execute-a-delegate-at-object-creation-time

Apr 24, 2013 at 4:50 PM