1

I'm trying to unit test a factory class that uses reflection to construct an unknown object that derives from a known base class.

However, I'm getting an exception when the factory tries to invoke the the constructor derived from my fake unit's type. It's a null reference exception.

I'm using FakeItEasy. Here's What I have going on here:

[TestFixture]
public class DisplayUnitFactoryTests
{
    private readonly IDisplayUnitPluginContainer _mgr = A.Fake<IDisplayUnitPluginContainer>();
    private readonly DisplayUnitPlugin _plgin = A.Fake<DisplayUnitPlugin> ();
    private DisplayUnit _unit;
    private Guid _guid;

    [TestFixtureSetUp]
    public void init()
    {
        _unit = A.Fake<DisplayUnit> (p=> p.WithArgumentsForConstructor(new object[]{new Dictionary<string,string>()}));
        _guid = Guid.NewGuid ();

        A.CallTo (() => _mgr.Resolve (VALID_STRING)).Returns (_plgin);
        A.CallTo (() => _mgr.Resolve (INVALID_STRING)).Returns (null);
        A.CallTo (() => _plgin.DisplayUnitType).Returns (_unit.GetType ());
    }

That bottom line is my issue. DisplayUnit is an abstract class. It's implementation shouldn't matter in this situation except for its constructor. However, DisplayUnit has a constructor that requires a Dictionary as a parameter.

If I use a REAL type (not faked), the code works fine. (e.g. A.CallTo(() => _plgin.DisplayUnitType).Returns(typeof(TextUnit)); However, That real type requires a dependency outside my core code. I want different types of DisplayUnits to be added at runtime as plugins. Thus, I want to unit test my DisplayUnitFactory using a fake Display Unit. In this test, I shouldn't need to depend on an outside assembly in order to make this work.

Here's my test.

[Test]
public void InstantiateNew_ValidPluginID_EmptyDict_ReturnsCorrectDisplayUnit()
{
    var factory = new DisplayUnitFactory (_mgr);

    var du = factory.InstantiateNew (VALID_STRING, new Dictionary<string, string> ());
    Assert.That (du, Is.Not.Null);
}

Here's my factory code:

public DisplayUnit InstantiateNew (string pluginId, Dictionary<string, string> attributes)
{
    return getDisplayUnit (pluginId, attributes);
}

private DisplayUnit getDisplayUnit(string pluginId, Dictionary<string,string> attributes)
{
    //Get the constructor that accepts only a dictionary<string,string>.
    var ctor = getCtor (pluginId, new Type[]{typeof(Dictionary<string,string>)});
    //Invoke it with the attributes dictionary.
    var unit = ctor.Invoke (new object[]{ attributes }) as DisplayUnit;
    return unit;
}

private ConstructorInfo getCtor(string pluginId, Type[] paramTypes)
{
    var plugin = _container.Resolve (pluginId);
    if (plugin == null)
        throw new NotRegisteredPluginException ("Plugin not registered: " + pluginId);
    var type = plugin.DisplayUnitType;
    return type.GetConstructor (paramTypes);
}

Essentially, I need to fake the ConstructorInfo that will come out using Reflection, and ultimately fake the return from ConstructorInfo.Invoke(). But I'm getting a null reference exception in getDisplayUnit() when the constructor is invoked, because the ctor is coming back null.

Help!

Jon Falkenstein
  • 135
  • 1
  • 9
  • Just so I think I understand, the constructor is coming back null because `_unit.GetType()` returns a type with only a paramterless constructor (or at least no publicly visible constructor with the right signature)? – Blair Conrad May 26 '16 at 19:49
  • It seems it's because a faked DisplayUnit doesn't provide any constructors to Reflection. Maybe? I really don't know. Bottom line, `_unit.GetType().GetConstructor(new Type[]{typeof(Dictionary)})` seems to be returning null. But only because _unit is `A.Fake()`. This actually works just fine if I use a real DisplayUnit. – Jon Falkenstein May 26 '16 at 19:52
  • 1
    Right. I was hoping you'd take a look at all the constructors displayed. I bet the fake only has a parameterless one. Or maybe no public one. Because why does it need constructors? It expects to be made by the `A.Fake` call. Unless you need to configure the behaviour of `_unit` (and I'm not sure how that would help, since the container's trying to make a new one anyhow), I'd just try to declare a subclass of `DisplayUnit` in my test project and use that. – Blair Conrad May 26 '16 at 19:55
  • As I was typing my response to your first comment, I begain to think that might be a good solution. I'd prefer to use fakes... but I guess there really isn't a difference if I'm essentially creating a dummy DisplayUnit class that only implements the bare necessities. Thanks for the pointer. – Jon Falkenstein May 26 '16 at 19:59

1 Answers1

3

So Thanks to Blair, I believe I've found the solution: It's not to use a Fake at all.

The faked type will have only a single public constructor, with arguments Castle.DynamicProxy.IInterceptor[], Dictionary<System.String,System.String>. Thus the whole process was breaking down when Reflection tried to get a constructor.

The solution was to create a DummyDisplayUnit that derived from DisplayUnit and use that instead. This worked just fine, without needing a fake.

I guess sometimes I try to abstract to the point where I miss the obvious solution...

Blair Conrad
  • 233,004
  • 25
  • 132
  • 111
Jon Falkenstein
  • 135
  • 1
  • 9