Question

I have this factory class and I want to test it correctly. Let's say I have an abstract class which have many child (inheritance).

As you can see in my Factory class the method BuildChild, I want to be able to create an instance of a child class at Runtime. I must be able to create this instance during Runtime because the type won't be know before runtime. And, I can NOT use Unity for this project (if so, I would not ask how to achieve this).

Here's my Factory class that I want to test:

public class Factory
{
    public AnAbstractClass BuildChild(Type childType, object parameter)
    {
        AnAbstractClass child = (AnAbstractClass) Activator.CreateInstance(childType);
        child.Initialize(parameter);
        return child;
    }
}

To test this, I want to find a way to Mock Activator.CreateInstance to return my own mocked object of a child class. How can I achieve this? Or maybe if you have a better way to do this without using Activator.CreateInstance (and Unity), I'm opened to it if it's easier to test and mock!

I'm currently using Moq to create my mocks but since Activator.CreateInstance is a static method from a static class, I can't figure out how to do this (I already know that Moq can only create mock instances of objects).

I took a look at Fakes from Microsoft but without success (I had some difficulties to understand how it works and to find some well explained examples).

Please help me!

EDIT:

I need to mock Activator.CreateInstance because I want to force this method to return another mocked object. The correct thing I want is only to stub this method (not to mock it).

So when I test BuildChild like this:

[TestMethod]
public void TestBuildChild()
{
    var mockChildClass = new Mock(AChildClass);
    // TODO: Stub/Mock Activator.CreateInstance to return mockChildClass when called with "type" and "parameter" as follow.
    var type = typeof(AChildClass);
    var parameter = "A parameter";

    var child = this._factory.BuildChild(type, parameters);
}

Activator.CreateInstance called with type and parameter will return my mocked object instead of creating a new instance of the real child class (not yet implemented).

Was it helpful?

Solution

Well, I am tempted to say that this is not something you need to mock as it should be trusted to be under test, but I guess if the type is from an external source library, then you might have problems...that being said, the only way you can achieve this is to wrap Activator so that it is not a static class.

Something like this:

public ActivatorWrapper
{
    public virtual object CreateInstance(Type type)
    {
        return Activator.CreateInstance(type);
    }
}

OTHER TIPS

You will have to introduce an interface which exposes a method to create the instance from the type. Have your class take an implementation of the interface in its constructor.

Then you can mock that.

You then have an implementation which just delegates to Activator.CreateInstance which you use in Production.

That said, why do you need to mock this? Why can't your test just check that it gets back the type that was specified in the method call?

Following On from your edit, why can't you mock the factory call to BuildChild rather than the call inside the factory. That seems like the dependency that you want to mock.

seems you either want to test that the factory returns the correct type, which you don't need to mock anything for, or you want to introduce an interface for your factory and mock that.

I think that wanting to mock Activator.CreateInstance is your code telling you that something is not quite right with your design.

you could test your factory implementation without having an implementation of AnAbstractClass or without needing to mock anything like this I think:

create a test implementation:

public class TestAnAbstractClass : AnAbstractClass
{
     public object ConstructorParameter;

     public TestAnAbstractClass(object constructorParameter)
     {
          this.constructorParameter = constructorParameter;
     }
}

then call your factory with this in your test:

[TestMethod]
public void TestBuildChild()
{
    var type = typeof(TestAnAbstractClass);
    var parameter = "A parameter";

    var child =(TestAnAbstractClass) this._factory.BuildChild(type, parameters);
    Assert.That(child.ConstructorParameter, Is.EqualTo(parameter));
}

Then you are testing the factories actual functionality and even if the implementation changes the test won't need to, and you test all the code.

You could try using an ambient context like the example below;

    public static class SystemActivator
    {
        private static Dictionary<Type, object> _mockObjects;

        private static Dictionary<Type, object> MockObjects
        {
            get { return _mockObjects; }
            set
            {
                if (value.Any(keyValuePair => keyValuePair.Value.GetType() != keyValuePair.Key))
                {
                    throw new InvalidCastException("object is not of the correct type");
                }
                _mockObjects = value;
            }
        }

        [Conditional("DEBUG")]
        public static void SetMockObjects(Dictionary<Type, object> mockObjects)
        {
            MockObjects = mockObjects;
        }

        public static void Reset()
        {
            MockObjects = null;
        }

        public static object CreateInstance(Type type)
        {
            if (MockObjects != null)
            {
                return MockObjects.ContainsKey(type) ? MockObjects[type] : Activator.CreateInstance(type);
            }
            return Activator.CreateInstance(type);
        }
    }

This is a very basic class to to give you the idea of the approach you could use. When testing you can set the MockObjects dictionary, pairing a type to an instance that you want to return (i.e. your mock object). Then instead of using Activator in the class you are constructing use SystemActivator.

Other advantages of this class is that you can unit test it to some degree e.g. test that it returns your mock when set and an activator instance when not.

Activator would never return an instance that had a different type to the one requested, SystemActivator should imitate this behaviour which is why I've included the exception. You could also consider throwing other errors (for example activator cannot create a string using the CreateInstance overload shown in this example but if you set MockObject to return a string value it will - this should not be allowed to happen)

There are dangers to this approach, you should never try to set MockObjects from production code. To reduce this danger I have given the method the [Conditional("DEBUG")] attribute. This would not stop a developer from trying to set MockObjects in production code, but it would cause the release build to break.

Also, in any test class that uses SystemActivator you need to include a teardown method that resets mock objects otherwise there is a danger of creating test dependencies.

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top