Martin
Martin

Reputation: 900

Injecting third party classes without creating factories

Lets say I have the following code in C#:

public class AppleTree
{
   public AppleTree()
   {
   }

   public string GetApple
   {
      return new Fruit("Apple").ToString();
   }
}

where Fruit is a third party class that does not have an interface.

I want to create a unit test for the AppleTree class but I do not want to run the Fruit class. Instead I would like to inject the Fruit class so that I can mock it in the tests.

How should I go about doing this? I can create a factory that creates apples and then add an interface to this factory like:

public class FruitFactory : IFruitFactory
{
   Fruit CreateApple()
   {
      return new Fruit("Apple");
   }
}

Now I can inject IFruitFactory into the AppleTree and use the CreateApple instead of new Fruit as:

public class AppleTree
{
   private readonly IFruitFactory _fruitFactory;

   public AppleTree(IFruitFactory fruitFactory)
   {
      _fruitFactory = fruitFactory
   }

   public string GetApple
   {
      return  _fruitFactory.CreateApple().ToString();
   }
}

Now to my question: Is there a good way of doing this without having to create the factory? Can I for example use a dependency injector famework like Ninject in some way?

Upvotes: 1

Views: 385

Answers (5)

Ruben Bartelink
Ruben Bartelink

Reputation: 61795

See Ninject.Extensions.Factory - with it, you have Func<T> ctor arguments and the Abstract Factory is generated behind the scenes (a la @Nenad's +1'd answer)

(You can also define an Abstract Factory interface and have Ninject.Extensions.Factory implement it.

Upvotes: 0

Travis
Travis

Reputation: 10547

You can mock out implemented types. The product that I know of that does this pretty well is Typemock. Microsoft has a product called Moles but I haven't met anyone who actually uses it. I don't have a lot of input into it's usefulness.

You can also register COM interfaces with the runtime to intercept object creation to inject your own. That's how these products work. These are the least amount of code change to get where you want.

Long term I would lean towards abstracting Fruit out with factories or the like. But tools like Typemock or Moles will get you there faster in the short term. It will just be less friction moving forward if everything is behind an interface.

Upvotes: 1

Michael Tsai
Michael Tsai

Reputation: 711

If you couldn't program to IFruit interface, then I think Abstract Factory is the way to go.

As to unit testing, if you are using Visual Studio 2012, you may try Microsoft Fakes. The following code is just for fun (it works of course). Maybe it's overkill for your case.

using Microsoft.QualityTools.Testing.Fakes;
using MyLib;

namespace UnitTestProject1
{
    [TestClass]
    public class UnitTest1
    {
        [TestMethod]
        public void TestMethod1()
        {
            using (ShimsContext.Create())
            {
                MyLib.Fakes.ShimFruit.ConstructorString = delegate(Fruit f, string s)
                {
                    var shimFruit = new MyLib.Fakes.ShimFruit(f);
                    shimFruit.ToString = () =>
                    {
                        return "Orange";
                    };
                };
                AppleTree tree = new AppleTree();
                string expected = "Orange";
                Assert.AreEqual(expected, tree.GetApple());
            }
        }
    }
}

Upvotes: 0

Nenad
Nenad

Reputation: 26647

Maybe, most simple, implement your own abstract FruitBase class, with virtual methods/properties. Then make implementation that wraps real Fruit class - FruitWrapper. Same logic as HttpContextBase, HttpContextWrapper and HttpContext in System.Web.

Then you can easily mock everything without any vendor-specific dark-magic testing framework.

public class AppleTree
{
    private readonly Func<FruitBase> _constructor;
    public AppleTree(Func<FruitBase> constructor)
    {
        _constructor = constructor;
    }

    public string GetApple()
    {
        return new _constructor().ToString();
    }
}

And you can swap functions in constructor: () => new FruitMock() and () => new Fruit("Apple").

Upvotes: 1

Zaid Masud
Zaid Masud

Reputation: 13443

Rather than the factory you would typically have Fruit implement an IFruit interface and inject that instead:

public class AppleTree
{
    private readonly IFruit _apple;

    public AppleTree(IFruit apple)
    {
        _apple = apple;
    }

    public string GetApple()
    {
        return _apple.ToString();
    }
}

With this kind of implementation you can instantiate either:

  1. new AppleTree(new Fruit("Apple")) or you could have an IoC container like NInject or StructureMap do it for you
  2. new AppleTree(mockApple) where mockApple is a mock IFruit object you've created for unit testing

Upvotes: 0

Related Questions