无法对调用静态方法的方法进行单元测试,如何重新设计该程序?

1 .net c# oop static unit-testing

我有一个类,它在整个程序中将日志写入文本文件.我认为制作方法是一个好主意,static因为它只有几个方法,并且在程序的许多不同部分被调用.在程序开始时调用此方法一次以创建初始文件.

public static void CreateAuditLog()
{
    var fileName = Path.Combine(filePath, 
        $@"AuditFile{DateTime.Now:yyyy-MM-dd_hh-mm-ss-fff}.txt");

    writer = new StreamWriter(new FileStream(fileName,
        FileMode.CreateNew, FileAccess.Write));

    GetAuditLogFileSize();
}
Run Code Online (Sandbox Code Playgroud)

但是在编写单元测试时,我不知道你不能测试一个调用静态方法的方法.(来自代码库的示例方法)

public Decimal CalculateCurrentBalance
{
    get
    {
        var balance = TotalAmountBilled - TotalAmountPaid;
        Audit.Message(2, $"Balance: {balance} for: {Name}");
        return TotalAmountBilled - TotalAmountPaid;
    }
}
Run Code Online (Sandbox Code Playgroud)

消息方法有很多细节,所以我不会在这里发布所有内容,但基本上它需要一个数字和一条消息来记录到文本文件.流编写器故意保持打开状态,CreateAuditLog()以便Message()可以在许多不同的地方调用,并将消息写入日志文件.

public static void Message(int auditLevel, string message)
Run Code Online (Sandbox Code Playgroud)

我觉得我设计这个程序的方式很糟糕.有没有人对我如何重新设计这个有任何建议?我不知道如果不在程序中的每个其他类上创建我的日志记录类的实例,我怎么能做到这一点.

Bra*_*NET 5

不要在每个其他类中创建实例; 注入一个.

这是单元测试的基础之一; 依赖注入.类不会创建或直接访问它们的依赖项,它们会传递给要使用的依赖项.在这种情况下,如果您的Log类已实现ILogger(您组成的界面),那么您的类将如下所示:

public class MyInjectedClass
{
     private readonly ILogger logger;
     public MyInjectedClass(ILogger logger)
     {
        this.logger = logger;
     }

     public void SomeMethod()
     {
        logger.Message();
     }
}
Run Code Online (Sandbox Code Playgroud)

当然,现在你必须传递一个ILogger遍布整个地方的实例,这是一个很大的麻烦.幸运的是,有许多类似的库NInject,Autofac它们将为您连接所有依赖项.这将需要一些重构,但是一旦完成,您只需将您的日志记录类注册为ILogger接口的单例,它将自动注入到将其作为依赖项的每个类中.

(如果您使用的话,MS有一个DI库以及.NET Core)

界面可能类似于:

public interface ILogger
{
     void Message(string msg);
}
Run Code Online (Sandbox Code Playgroud)