C# – How to mock this architecture

cenummocking

This is not a very general question, so it may not exactly be appropriate here, but I could sure use a suggestion if you have one:

I have an object containing a dictionary keyed off of an enum, something like this:

namespace Application
{
    public enum Material { H20, CO2, Na }
    public class Container
    {
        private Dictionary<Material, ChemicalComponent> dic;
        public Container(Dictionary<Material, ChemicalComponent> d)
        {
            dic = d;
        }
    }
}

I now want to create a MockContainer and a MockMaterial, but I can't figure out how to make it all work together. The following code, for example, does not work (see comment):

using Application;  
namespace UnitTesting
{
    public enum mockMaterial { mock1, mock2, mock3 }
    public class mockContainer : Container
    {
        public mockContainer(Dictionary<mockMaterial, ChemicalComponent> d)
            : base(d) // compiler error: the base constructor "has some invalid arguments"
        {
        }
    }
}

Originally I had hoped to extend the Material enum inside the UnitTesting namespace; then I could just use the Container's Dictionary, but with different keys. But of course, that isn't legal in C#. Is there some non-kludgy way to overload or inject a Dictionary with the mock enum keys?

Update: One option is to change the dictionary definition to this:

private Dictionary<Enum, ChemicalComponent> dic;

(i.e., change the key type to Enum throughout the code). This works (i.e., eliminates the compiler error), but this solution sacrifices clarity as well as type-safety. (It is no longer clear what the key is intended to be).

Update #2:
Several people have recommended that I create an interface for Container. But that misses the point. The container itself is not all that complex. But the ChemicalComponents that are stored in it are very complex. I need to mock those in my unit tests, but I don't know how to do that without extending the enum that serves as the key.

Best Answer

I now want to create a MockContainer and a MockMaterial, but I can't figure out how to make it all work together.

Why?

I mean, the purpose of test objects (mocks, fakes, stubs, etc.) are to remove some dependency in your code so you can test while ignoring the dependency. Material is an enum. That's not some sort of dependency that is going to break your tests. Making some inglorious hack is more likely to break your tests (and your production code).

If you want a mock container (I'm assuming your container is more than being an alias to Dictionary<Material, ChemicalComponent>), then you should provide some interface to the container, and mock that.

And remember:

  • If the code is hard to test, it's probably hard to use (see, lack of interface making it inflexible for a different implementation).
  • The tests are there to serve you, not vice versa. Don't do things blindly because you should. Do them because they make your life easier.