I am quite new to unit testing. Though I can do simple unit test, I am finding it difficult to understand the dependency injection part. I have 2 scenarios where I could not create the test
Though I searched the internet and I could not find any simple example to follow and implement these mocking.
Can Moq supports concrete class or should I need to change all my implementation into virtual for unit testing. Any example code or link for the sample code is much appreciated
First of all, Moq does not support mocking concrete classes. Only abstract classes and interfaces can be mocked. However, this is not as hard as it sounds. Let's take your log file handling as an example.
Say you start with the following concrete logging class:
public class Log
{
public void WriteToLog(string message)
{
...
}
}
We have another classes that uses this Log
class to do its logging:
public class LogGenerator
{
public void Foo()
{
...
var log = new Log();
log.WriteToLog("my log message");
}
}
The problem with unit testing the Foo
method is that you have no control over the creation of the Log
class. The first step is to apply inversion of control, where the caller gets to decide what instances are used:
public class LogGenerator
{
private readonly Log log;
public LogGenerator(Log log)
{
this.log = log;
}
public void Foo()
{
...
this.log.WriteToLog("my log message");
}
}
Now we are one step closer to successfully unit testing as our unit test can choose which Log
instance to do the logging with. The last step now is to make the Log
class mockable, which we could do by adding an interface ILog
that is implemented by Log
and have LogGenerator
depend on that interface:
public interface ILog
{
void WriteToLog(string message);
}
public class Log : ILog
{
public void WriteToLog(string message)
{
...
}
}
public class LogGenerator
{
private readonly ILog log;
public LogGenerator(ILog log)
{
this.log = log;
}
public void Foo()
{
...
this.log.WriteToLog("my log message");
}
}
Now we can use Moq in our unit test to create a mock of an object implementing ILog
:
public void FooLogsCorrectly()
{
// Arrange
var logMock = new Mock<ILog>();
var logGenerator = new LogGenerator(logMock.Object);
// Act
logGenerator.Foo();
// Assert
logMock.Verify(m => m.WriteToLog("my log message"));
}
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