简体   繁体   English

调用static方法是否是单元测试的测试用例?

[英]Is a call of the static method is a test case for unit testing?

This is a simplified model of my class. 这是我班上的简化模型。

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

ApplicationLogger is a static class which is used across the solution. ApplicationLogger是在解决方案中使用的静态类。 How can I verify that error was logged? 如何验证已记录错误?

This is example of my test method. 这是我的测试方法的示例。

[TestMethod]
public void CreateFooExpectedError()
{
    // Arrange
    string testUrl = "fakeUrl";

    // Act
    FooFactory.CreateFoo(testUrl);

    // Assert
    /ApplicationLogger.LogError();
}

How to check that LogError method was called? 如何检查LogError方法是否被调用? Does it a test case? 它是一个测试用例吗?

You have a hard dependency on ApplicationLogger . 您对ApplicationLogger有严格的依赖性。 That's not good. 这不好。 Now you can't test that CreateFooByUrl works without actually logging something. 现在,如果不实际记录某些内容,就无法测试CreateFooByUrl有效。 Instead, have it use an IApplicationLogger (an interface) and then you can provide a mock implementation of that interface as part of unit testing. 相反,让它使用IApplicationLogger (接口),然后可以在单元测试中提供该接口的模拟实现。 This will probably mean you either need to make FooFactory non static (you can't have a non static method in a static class anyways like you've shown) or change CreateFooByUrl to accept an IApplicationLogger as a parameter (messier). 这可能意味着您需要使FooFactory非静态的(无论如何都不能在静态类中使用非静态方法,就像您显示的一样),或者更改CreateFooByUrl以接受IApplicationLogger作为参数( IApplicationLogger )。

Here's the clean way: 这是干净的方法:

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>()));
}

This is much better from a Separation of Concerns perspective. 从“关注分离”的角度来看,这要好得多。 Why should FooFactory care how things get logged? 为什么FooFactory应该关心如何记录事情? It just needs to be able to log things. 它只需要能够记录事物。 That's why it's better to code against an interface. 这就是为什么最好对接口进行编码。 Then if you ever want to switch logging implementations you just have to create a new class that implements IApplicationLogger and everything will magically work. 然后,如果您要切换日志记录实现,则只需创建一个实现IApplicationLogger的新类,一切便会神奇地工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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