2

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).

Jeep87c
  • 1,050
  • 16
  • 36

3 Answers3

5

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);
    }
}
Justin Pihony
  • 66,056
  • 18
  • 147
  • 180
  • You're totally right when you say that this should be trusted and so I don't need to mock it. I just edit my post to explain why I need to mock this class. – Jeep87c Jun 28 '13 at 22:04
  • @Jeep87c That is why I also gave the workaround to this. Unless you want to go into the more powerful frameworks...but those promote bad OO behavior – Justin Pihony Jun 28 '13 at 22:12
  • Oh sorry, you probably edited your post while I was editing mine. Never mind and thank you for this workaround. I don't want to use more powerful frameworks because of the reason you said. – Jeep87c Jun 28 '13 at 22:19
1

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.

Sam Holder
  • 32,535
  • 13
  • 101
  • 181
  • Because the purpose of the test itself is to test the Factory class and its methods. Mocking the factory call would just end in an useless test. I already mock this factory when I test other class using it. – Jeep87c Jun 28 '13 at 22:21
  • And also, for you question "Why can't your test just check that it gets back the type that was specified in the method call?" because the child class are not yet implemented and, by definition, a unit test on a class should never depends on other class. – Jeep87c Jun 28 '13 at 22:23
  • 1
    But it's turtles all the way down. If you introduce an class which wraps Activator.CreateInstance how are you going to test that implementation? I suppose you will be able to test that the object returned had its initialize method called. But an initialize method is a smell and should be avoided. Parameter should probably be passed through the constructor declared on your abstract class (as it seems that parameter is not optional) instead which would make this method 'empty' as it would simply wrap the call to Activator.CreateInstance (parameter) – Sam Holder Jun 28 '13 at 22:30
  • @jeep87c I think your trying to work around another problem in your code. But wrapping the function will work. – Sam Holder Jun 28 '13 at 22:43
  • Your comment is more then right! It's turtles it all the way down like you said but, I can live a class as @JustinPihony suggested not tested since it's only a wrapper of one static method. But I cannot with my factory not tested. You're also more then right about "parameter". It should be passed directly to the constructor. I'll look a little bit more to CreateInstance method to see how to pass there my parameter to the constructor. – Jeep87c Jun 28 '13 at 23:05
  • A quick Google search gave me this [link](http://stackoverflow.com/questions/2451336/how-to-pass-parameters-to-activator-createinstancet) – Jeep87c Jun 28 '13 at 23:14
  • yeah to invoke the constructor which takes an argument just pass the constructor argument to `Activator.CreateInstance(parameter)` and it will invoke the first matching constructor it finds. Once you've done this its arguable if the wrapper gives you anything, and you'd be better to test this method by creating a dummy implementation of AnAbstractClass in the tests and passing that type. I'll edit the post to show an example – Sam Holder Jun 29 '13 at 06:28
0

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.

mark_h
  • 5,233
  • 4
  • 36
  • 52