Friday, September 28, 2012

Using Thoughtbot's factory_girl for Ruby in .net unit test setup methods


FactoryGirl is a fixtures replacement with a straightforward definition syntax, support for multiple build strategies (saved instances, unsaved instances, attribute hashes, and stubbed objects), and support for multiple factories for the same class including factory inheritance. James Kovacs has created a nice implementation of the FactoryGirl class in .NET. You can follow this link to check out his article on implementing the FactoryGirl in .NET. I have extended the FactoryGirl implementation by using Moq to register and invoke stubs to use in unit test methods.

public class FactoryGirlStubs
{

    private static readonly IDictionary<Type, object> stubs = new Dictionary<Type, object>();

    public static IEnumerable<Type> DefinedStubs
    {
        get { return stubs.Select(x => x.Key); }
    }

    public static void ClearStubDefinitions()
    {
        stubs.Clear();
    }

    public static void ClearStub()
    {
        stubs.Remove(typeof(T));
    }

    public static T BuildStub() where T : class
    {
        var result = (T)stubs[typeof(T)];
        return result;
    }

    public static void DefineStub() where T : class
    {
        var mock = new Mock();
        mock.SetupAllProperties();
        if (stubs.ContainsKey(typeof(T))) throw new DuplicateStubException();
        stubs.Add(typeof(T), mock.Object);
    }

    public static void DefineStub(Expression<Action> expression) where T : class
    {
        var mock = new Mock();
        mock.Setup(expression);
        mock.SetupAllProperties();
        if (stubs.ContainsKey(typeof(T))) throw new DuplicateStubException();
        stubs.Add(typeof(T), mock.Object);
    }

    public static void DefineStub(Expression<Func> expression, TResult result) where T : class
    {
        var mock = new Mock();
        mock.Setup(expression).Returns(result);
        mock.SetupAllProperties();
        if (stubs.ContainsKey(typeof(T))) throw new DuplicateStubException();
        stubs.Add(typeof(T), mock.Object);
    }
}

Test methods

[TestMethod]
public void DefineAddsTheStubsToTheStore()
{
    FactoryGirlStubs.DefineStub<ICustomerRepository>();
    Assert.IsTrue(FactoryGirlStubs.DefinedStubs.Any(x => x.Name.Contains("ICustomerRepository")));
    FactoryGirlStubs.ClearStubDefinitions();
}

[TestMethod]
public void BuildShouldReturnTheDefinedStubFromStore()
{
    FactoryGirlStubs.DefineStub<ICustomerRepository>();
    var repository = FactoryGirlStubs.BuildStub<ICustomerRepository>();
    Assert.IsInstanceOfType(repository, typeof(ICustomerRepository));
    FactoryGirlStubs.ClearStubDefinitions();
}
       
[TestMethod]
public void DefineWithSetupRegistrationsShouldReturnResultwhenSetupMethodIsInvoked()
{
    FactoryGirlStubs.DefineStub<ICustomerRepository, Customer>(x => x.GetById(1), new Customer { FirstName = "Prajeesh" });
    var repository = FactoryGirlStubs.BuildStub<ICustomerRepository>();
    Assert.IsTrue(repository.GetById(1).FirstName == "Prajeesh");
    FactoryGirlStubs.ClearStubDefinitions();
}

1 comment:

Anonymous said...

Admiring the commitment yοu put іntο youг blog and
detaileԁ infοrmation you offeг.

It's awesome to come across a blog every once in a while that isn't the sаme old rеhashed
matеrіal. Great reaԁ! I've saved your site and I'm addіng your RSS feedѕ to my Gοogle аccоunt.
my web site :: craigslist phone verification