Search code examples
c#unit-testingdependency-injectionmef

Unit test mocking base class


Need some help to see if I have anyway to test this stuff.

So I have an app that uses MEF plugins, the plugin accepts an Interface with several props, one of those props it's a ActionType.

Then in this specific plugin, the main objective it's to execute some action, the action itself it's writing stuff in different places, the places and the values depends on the action.

So I have a interface let's call it IBaseAction that only has one method, SendAction, that accepts some parameters:

public interface IBaseAction{
 bool SendAction(string actionName, string actionPlace, string actionValue)
}

Then I have this base class, that implements the interface, and where it has the logic to write, to check and to log everything.

public class BaseAction:IBaseAction
{
 public virtual bool SendAction(string actionName, string actionPlace, string actionValue)
 {
   //Something something... 
 }
}

So for each action available I have a new Action class that derives from the Base class and overrides de base method, that for each of one of them, it performs some logic before calling the base SendAction method.

public class ActionA:BaseClass
{
 public override bool SendAction(string actionName, string actionPlace, string actionValue)
 {
     //Some logic... Transformations... Custom Data Preparations...
     base.SendAction(actionName,actionPlace,actionValue)
 }
}

The entry point of the app/plugin, I will have a switch statement that instantiates the correct Action, kind like this:

IBaseAction baseAction;
switch (ActionType)
{
  case "A":
    baseAction = new ActionA();
    break;
  case "B":
    baseAction = new ActionB();
    break;
  //Other cases... 
}

Then I just call the baseAction.SendAction(...);

Now I'm trying to create unit tests for this, so I need to know if I somehow can mock, replace, whatever, the base class?

I just need to test the different Actions logic and then mock the job of the base class, returning true or false at my pleasure.

Inside the base class, I'm newing some stuff, I cannot inject them from outside of the plugin itself.

Thanks


Solution

  • I don't think you can mock a base class. You will need to break the behaviour in order to replace it. I suggest a few alternatives that can be of use to find your own way. First two require to make changes to the base class. The third one requires no change.

    Strategy pattern

    Using a strategy pattern doesn't require any additional libraries. This could be a sample implementation.

    public interface ISendStrategy {
        bool SendAction(string actionName, string actionPlace, string actionValue);
    }
    
    public class BaseAction: IBaseAction {
    
        // make this visible to your test project with InternalsVisibleTo
        internal ISendStrategy SendActionStrategy {get; set;}
    
        public BaseAction() 
        {
            this.SendActionStrategy = new SomeDefaultImplementation();
        }
    
        public virtual bool SendAction(string actionName, string actionPlace, string actionValue) 
        { 
            this.SendActionStrategy.SendAction (....)
        }
    }
    

    For testing you will provide a fake strategy that suits your needs. You can adapt this to your own liking: Use a setter, inject the strategy in the constructor, etc...

    Use a mocking framework

    Now, if you're using some mocking library like NSubstitute you can do something like this.

    public class BaseAction: IBaseAction {
    
        public virtual bool SendAction(string actionName, string actionPlace, string actionValue) 
        {
            this.SendActionImplementation (....)
        }
    
        public virtual bool SendActionImplementation (string actionName, string actionPlace, string actionValue) 
        {
            // the real thing.
        }
    }
    

    Then, in your test, you can use a partial mock:

    var substitute = Substitute.ForPartsOf<ActionA>()
    subsitute.Configure().SendActionImplementation (default,default,default).ReturnsForAnyArgs(false); 
    

    Not that I like SendActionImplementation being public or virtual. Making it internal virtual could cause problems according to the docs. I would go with the first method.

    Bridge Pattern

    Make ActionA to implement the bridge pattern, but not to extend the base class

    public ActionA: IBaseAction {
    
        private IBaseAction real;
    
        public ActionA (IBaseAction base) {
            this.real = base;
        }
    
        public bool SendAction(...) 
        {
            // custom
            return this.real.SendAction()
        }
    
        // and the remaining methods as well
    
    }
    

    If the interface has many methods you can create an intermediate class with all of them, and make ActionA replace only the methods that you need. This is a very neat solution that works without making changes to the original class, which is great if you don't own it. You can use the original class as a parameter for the constructor, a partial mock or a complete fake.

    Disclaimer: I wrote the examples on the fly so they could need some fixing, but I think you can get the idea.