Search code examples
c#unit-testing.net-4.0moqmvp

Instance of an object created in a method. How to mock that instance?


I have a method in my Presenter which creates a class which contains all the user inputs, called UserInputEntity. It implements the interface IUserInputEntity. I currently have it declared as a local variable, of type UserInputEntity, and thus can't mock it in the following method (simplified for brevity):

public void CompletionReportNotifier(object sender, VerificationStatusEventArgs e)
{
    _view.PermanentCsvFileVerificationCancellation = null;

    string logMessage;
    bool inputsVisible = false;

    //Mocking inputs.NumberOfErrorsFound??
    if (e.CarriedOutToCompletion != true || inputs.NumberOfErrorsFound > 0)
    {
        inputsVisible = true;
        _view.VerificationCompleted = false;
        logMessage = "failed to complete operation";
    }
    else
    {
        _view.VerificationCompleted = true;
        logMessage = "Completed operation";
    }
    _view.UIUpdate(logMessage, inputsVisible);
}

What is the most appropriate way to get around this? The only possible solution I can think of is to declare another method which only calls the entity classes constructor, and returns an IUserInputEntity. I would then change the declaration of inputs, in the presenter, to type IUserInputEntity. Would this be suitable or is there a better way?

Below is a copy of the method where the instance of inputs is created currently (simplified):

private void DataVerification(Object sender, EventArgs e)
{
    if (_view.VerifyingData != true)
    {
        inputs = new UserInputEntity(_view.DataTypeInputs, _view.ColumnNameInputs, _view.InitialRow, _view.FinalRow, _view.CurrencyPair, _view.CsvFilePath, _view.ErrorLogFilePath);

        // ...

        verification.VerifyDataTypesAsync();     
    }
    else
    {
        _view.PermanentCsvFileVerificationCancellation.Cancel();
    } 
}

Solution

  • When following a dependency injection pattern, any usage of the keyword 'new' should be met with extreme caution and trepidation. Chances are fantastic it is exactly one of those dependencies that should be injected. This is definitely one of those times.

    The real solution here is to add IUserInputEntity to your constructor and abstract it away for your inversion of control container (StructureMap, NInject, etc) to inject automatically. In structuremap, this would look a little like this:

    public class DependencyRegistry : Registry
    {
        public DependencyRegistry()
        {
            For<IUserInputEntity>().Use<UserInputEntity>();
        }
    }
    

    With the class usage:

    public MyClass(IUserInputEntity userInputEntity)
    {
       _userInputEntity = userInputEntity;
    }
    

    You may then set properties as you know them or use them freely in your concrete class. In your test, it will look something like this (presuming NUnit and RhinoMocks):

    [Test]
    public void MyTest()
    {
       var mockEntity = MockRepository.GenerateMock<IUserInputEntity>();
    
       var testedClass = new MyClass(mockEntity);
    }
    

    At this point you may do whatever you please to train the mock entity using the various control methods provided with RhinoMocks, or whatever your mocking framework is. The important thing to note here is that you are not passing in a concrete implementation of UserInputEntity that functions how you programmed a concrete to function. You are passing in a mock that will do exactly what you tell it to do, and nothing more.