简体   繁体   中英

How to use Moq on singleton classes so that we can only test Business logic and ignore logging

 public class SLogger
 {
     private const string SSchemasFileName = "sSchemas";
     private const string SLogsFileName = "sLogs";

     private static string logsDir = @"D:\Data\logs\local\";
     private static readonly Lazy<SLogger> instance = new Lazy<SLogger>(() => new SLogger());

     private ESC eSC;
     private AEL aEL;

     private SllLogger()
     {
         eSC= new ESC(logsDir , SSchemasFileName);
         aEL= new AEL(logsDir , SLogsFileName, EventLevel.Verbose);
     }

     public static SLogger Instance
     {
         get
         {
             return instance.Value;
         }
     }

     public void LogInformation()
     {
         // Some logic here
     }
}

How can I use Moq framework to just test the business logic and ignore the logging library code?

For example if I have some class which has a method as shown below and I want to unit test this method using Moq framework or any other framework then how can I Moq this singleton class?

Is there any other way I can do it?

void foo()
{
   // Business logic

   SLogger.Instance.LogInformation();

   // Business logic
}

Without having an abstraction to depend on instead of a tight coupling to SLogger , there's no way to test foo() independently.

I'd suggest you define an interface for SLogger to implement; minimally, given your example:

public interface ILogger
{
    void LogInformation();
}

I'd further suggest you provide an instance of ILogger in your class' constructor, as a form of dependency injection , and have your class invoke methods of the injected dependency:

public class Bar
{
    private readonly ILogger _logger;

    public Bar(ILogger logger)
    {
        _logger = logger;
    }

    public void Foo()
    {
        _logger.LogInformation();
    }
}

From your calling code, you can now provide a real implementation of ILogger , be it a singleton instance of SLogger , or a mock for a unit test:

//Real call
var myBar = new Bar(SLogger.Instance);

//From a test
var testBar = new Bar(new Mock<ILogger>().Object);

There are plenty of resources across Stack Overflow and on the web to learn about dependency injection and inversion of control patterns, but Mark Seemann's blog is a good starting point.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM