uchagani / factory-girl

A library for setting up .NET objects as test data.
MIT License
10 stars 6 forks source link

Need documentation for associations #7

Open sslotsky opened 9 years ago

sslotsky commented 9 years ago

The README does not show how to do associations with this package. For example if I have models Foo and Bar

public class Foo
{
    public Guid BarID { get; set; }
    public Bar Bar { get; set; }
}

public class Bar
{
    public string Name { get; set; }
}

And I have a factory for Bar

public class BarFactory : IDefinable
{
    public void Define()
    {
        FactoryGirl.Define<Bar>(() => new Bar
        {
            Name = "Baz"
        });
    }
}

Then how do I assign Bar in FooFactory?

public class FooFactory : IDefinable
{
    public void Define()
    {
        FactoryGirl.Define<Foo>(() => new Foo
        {
            Bar = // ????
        });
    }
}
uchagani commented 9 years ago

You'd have to build or create a Bar object and assign it. Have you tried doing

    FactoryGirl.Define<Foo>(() => new Foo
        {
            Bar = FactoryGirl.Build<Bar>();
        });

Ideally you would do this in a callback, which themselves have to be documented. If you look at the tests you can see how to use Callbacks. Currently we support AfterBuild, BeforeCreate, AfterCreate. I'll try and get the Callbacks documented this weekend.

sslotsky commented 9 years ago

Thanks for your reply. I considered doing that but there are a few things that make this cloudy for me that maybe I should have mentioned in the post.

  1. Your documentation implies that factories need to be initialized, e.g. FactoryGirl.Initialize(typeof(UserFactory));. After creating multiple factories, however, it seemed that initializing a single factory would initialize all of my defined factories, so therefore initializing both a FooFactory and a BarFactory will cause both to be initialized twice, resulting in error. All this confusion led me to question whether or not factories should be assuming that other factories have been initialized.
  2. Using Build inside a factory led to questions about whether or not the association would be persisted if I used FactoryGirl.Create<Foo>() rather than Build. I realize now that this seems to depend purely on how I implement Save for the IRepository interface, which leads me to my next point.
  3. While I'm admittedly new to dealing with persistence in a .NET application, it seems to me that having a model implement its own Save method is not something that's typically done, at least not with Entity Framework. I'm having trouble reconciling this requirement with the various strategies used with DbContext implementations. FactoryGirl is creating my models such that they are detached from any DbContext. In order to get Save to work on my model, it seems that my model has to know about the DbContext in which it was constructed. Are you able to provide any code samples that demonstrate how you might deal with this?
uchagani commented 9 years ago

You are correct in that calling Save on the model is not the .NET way to do things (via DbContext). I implemented this to mirror the ActiveRecord pattern where the Model is coupled to the persistence strategy.

I am open to modifying this package to take DbContext into account but do not have the time to make those changes at this time. If you could like to submit a Pull Request, I'll gladly take a look and merge it in.

sslotsky commented 9 years ago

That's a possibility. Are you familiar with NBuilder? This tool expects persistence behavior to be defined by a service level object rather than the model itself. Making that small change would put factory-girl in better alignment with .NET practices.

https://code.google.com/p/nbuilder/wiki/Overview_HowTo#Persistence

uchagani commented 9 years ago

This is definitely possible. It may require a bit of refactoring which needs to be done anyway to be honest. If you have the time and the inclination to add the repository to the persistence I'll gladly take a look at it. If not, I'll try to get around to it as soon as some time frees up.