是静态方法的调用是单元测试的测试用例



这是我类的简化模型。

public static FooFactory
{
    public void CreateFooByUrl(string url) 
    {
        try 
        {
           // business logic
        }
        catch(Exception exc) 
        {
           ApplicationLogger.LogError(exc);
        }
    }
}

ApplicationLogger是在整个解决方案中使用的静态类。如何验证是否记录了错误?

这是我的测试方法的示例。

[TestMethod]
public void CreateFooExpectedError()
{
    // Arrange
    string testUrl = "fakeUrl";
    // Act
    FooFactory.CreateFoo(testUrl);
    // Assert
    /ApplicationLogger.LogError();
}

如何检查是否调用了LogError方法?它是测试用例吗?

你对ApplicationLogger有很强的依赖性。那不好。现在,如果不实际记录某些内容,就无法测试CreateFooByUrl是否正常工作。相反,让它使用IApplicationLogger(接口(,然后您可以在单元测试中提供该接口的模拟实现。这可能意味着你需要FooFactory非静态的(无论如何,你不能像你展示的那样在静态类中使用非静态方法(,或者更改CreateFooByUrl以接受IApplicationLogger作为参数(混乱(。

这是干净的方法:

public interface IApplicationLogger
{
    void LogError(Exception exception);
}
public class ApplicationLogger : IApplicationLogger
{
    public void LogError(Exception exception)
    {
        //do stuff
    }
}
public class FooFactory
{
    private readonly IApplicationLogger _logger;
    public FooFactory(IApplicationLogger logger)
    {
        _logger = logger;
    }
    public void CreateFooByUrl(string url) 
    {
        try 
        {
           // business logic
        }
        catch(Exception exception) 
        {
           _logger.LogError(exception);
        }
    }
}
//now for the unit test
public void TestCreate()
{
    //arrange
    var mockLogger = new Mock<IApplicationLogger>(MockBehavior.Strict);
    mockLogger.Setup(m => m.LogError(It.IsAny<Exception>()));
    var factory = new FooFactory(mockLogger.Object);
    //act
    factory.CreateFooByUrl("something that will cause exception");

    //assert
    mockLogger.Verify(m => m.LogError(It.IsAny<Exception>()));
}

从关注点分离的角度来看,这要好得多。为什么FooFactory要关心事情是如何被记录下来的?它只需要能够记录事情。这就是为什么最好针对接口进行编码的原因。然后,如果你想切换日志记录实现,你只需要创建一个实现IApplicationLogger的新类,一切都会神奇地工作。

最新更新