It is possible to test if a method has been called using Moq and dependency injection. However, is it possible to test if one method in a class calls another within the same class?
For example, I want to test that if I log a certain exception, that an information message is logged as well.
The method is:
public void Error(string message, Exception exception, long logId = 0)
{
var int32 = (int)logId;
Info("Id was converted to an int so that it would fit in the log: " + logId, int32);
Error(message, exception, int32);
}
This was my attempt at unit testing it. The test fails, is there any way that it can it be done?
void logging_an_error_with_a_long_id_also_logs_info()
{
var mock = new Mock<ILogger>();
var testedClass = new Logger();
var counter = 0;
testedClass.Error("test" + counter++, new Exception("test" + counter), Int64.MaxValue);
mock.Verify(m => m.Info(It.IsAny<string>(), It.IsAny<int>()));
}
Since the Info
and Error
methods are in the same class (ClassA), I don't believe I can pass ClassA as a dependency into ClassA. So does it not need tested?
The best you're going to be able to do is to make Info
virtual
. This will allow you to create a Mock<Logger>
, set CallBase = true
, and verify that Info
was called.
var mock = new Mock<Logger>
{
CallBase = true
};
mock.Object.Error("test" + counter++, new Exception("test" + counter), Int64.MaxValue);
mock.Verify(m => m.Info(It.IsAny<string>(), It.IsAny<int>()));
This way, you're still calling the actual implementation of Error
, but you've used Moq to verify the Info
method was called.
It feels like you're trying to test the wrong thing. It's not really important that the Info
method on your class is called from the Error
method, what's important is that the behaviour of the Info
method occurs. How it happens is an implementation detail of the class.
If I had a math class with two functions:
public int Mult(int x, int y) {
return x*y;
}
public int Sqr(int x) {
return Mult(x,y);
}
I wouldn't test that calling Sqr
called out to the Mult
function, I would test Sqr(4)==16
. It doesn't matter if that calculation takes place in the Sqr method, or in another method of the class.
Whilst @Andrew's solution is probably what you're after, mocking the class you're testing tends to lead to tightly coupled, brittle tests.
If it's impractical to test the call by observing it's side effects, then it may be a sign that the implementation could use a bit of refactoring.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With