Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Moq simple example required- database connection and file handling

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

  1. Database connection
  2. Log file handling

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

like image 606
karpanai Avatar asked Jul 17 '13 12:07

karpanai


1 Answers

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"));
}
like image 174
Erik Schierboom Avatar answered Sep 24 '22 01:09

Erik Schierboom