moctopus moctopus - 3 months ago 11
C# Question

When using Moq, are mocked interfaces implemented methods supposed to execute?

I am new to using Moq and have not unit tested in about 5 years. Many things have changed.

I'm trying to wrap my head around the basics.

I have an interface.

public interface ILogger
{
void Log(string message)
}


And this interface is implemented in the following way.

public class MyLogger : ILogger
{
public virtual void Log(string message)
{
StaticClass.StaticMethodNotToBeCalled<ILogger>().Log(message);
}
}


I am testing the following logic.

public class MyClass
{
public MyMethod(int z)
{
var logger = new MyLogger();

if(z == 5)
{
logger.Log("it is true");

return true;
}

logger.Log("it is false);

return false;
}
}


My test looks like the following.

[TestMethod]
public void Test_MyMethod()
{
var mock = new Mock<ILogger>();

mock.Setup(y => y.Log(It.IsAny<string>()).Verifiable();

var o = new MyClass();

var result = o.MyMethod(5);

Assert.IsTrue(result);

mock.Verify();

}


The issue I am running into is the static method being called in the implementation of the ILogger interface.

I am guessing I just do not have a good understanding on what exactly a mock should.

What I would like to do is that any time ILogger.Log it is overridden and does not call that static method.

Is this possible?

Am I going about this a wrong way?

Answer

You're creating a Mock based on the ILogger interface, but you are not injecting the Mock into your MyClass instance. When MyClass executes it uses an instance of Logger instead of your ILogger mock.

Consider something like this for your class instead:

public class MyClass
{

    private ILogger logger;
    public MyClass(ILogger loggerInstance)
    {
        logger=loggerInstance;
    }
    public MyMethod(int z)
    {

        if(z == 5) 
        {
           logger.Log("it is true");

           return true;
        }

        logger.Log("it is false);

        return false;
    }
}

Note that in the constructor of MyClass you are now accepting an instance of an object that mocks the ILogger interface. This allows you to inject your mock object in place of the actual concrete Logger:

[TestMethod]
public void Test_MyMethod()
{
    var mock = new Mock<ILogger>();

    mock.Setup(y => y.Log(It.IsAny<string>()).Verifiable();

    var o = new MyClass(mock.Object);

    var result = o.MyMethod(5);

    Assert.IsTrue(result);        

    mock.Verify();

}

Dependency injection is the concept that you're missing in your scenario. It is imperative in many cases to writing unit-testable code.

If it's the actual static method call you need to mock and not the instance of Logger you can use reflection work around the issue, but in that case I would suggest that you have some underlying design issue that's making this difficult for you.

Comments