简体   繁体   English

如何模拟对象在测试方法之外初始化的方法?

[英]How to mock a method whose object is initialized outside of the testing method?

I have a class as我有一个班级

public class Authentication {
    private Timer timer;

    public Authentication(){
        // constructor
    }

    public void authenticate(){
        // Initialize timer in this method
        timer = new RouterTimer(FAKE_PARAM);
        testingMethod();
    }

    @VisibleForTesting
    void testingMethod(){
        timer.method();
        // other stuff
    }
}

I have a Timer object as a class attribute, but it isn't initialized in constructor, it gets initialized in authenticate().我有一个 Timer 对象作为类属性,但它没有在构造函数中初始化,而是在 authentication() 中初始化。

I'm writing unit test for testingMethod() , but the tests failed because the timer is null and calling the method() will throw an NullPointerException.我正在为testingMethod()编写单元测试,但测试失败,因为timer为空并且调用 method() 将抛出 NullPointerException。 I can't get the timer initialized with the constructor of the class.我无法使用类的构造函数初始化计时器。 I can't call authenticate() to initialize because that method will call testingMethod() .我无法调用authenticate()进行初始化,因为该方法将调用testingMethod()

How do I mock or do something else in this case?在这种情况下,我如何模拟或做其他事情?

Why are you trying to test private method?你为什么要测试私有方法? Split your code into logical parts and test them separately.将您的代码拆分为逻辑部分并分别进行测试。 Moreover, you are breaking SRP ( https://en.wikipedia.org/wiki/Single-responsibility_principle ).此外,您正在破坏 SRP ( https://en.wikipedia.org/wiki/Single-responsibility_principle )。 Method authenticate() should not initialize anything.方法 authenticate() 不应该初始化任何东西。

You generally don't unit test private methods directly.您通常不会直接对私有方法进行单元测试。 Since they are private, consider them an implementation detail.由于它们是私有的,因此将它们视为实现细节。 Nobody is ever going to call one of them and expect it to work a particular way.没有人会打电话给他们中的一个并期望它以特定的方式工作。 You should instead test your public interface.您应该改为测试您的公共接口。 If the methods that call your private methods are working as you expect, you then assume by extension that your private methods are working correctly.如果调用您的私有方法的方法按您的预期工作,那么您可以通过扩展假设您的私有方法正常工作。

You can change your constructor to receive a Timer object and that should be provided by the upper level where this class instance is created in the code.您可以更改构造函数以接收 Timer 对象,该对象应由在代码中创建此类实例的上层提供。

In your test, you can create a mock Timer object and pass it when you create the class instance.在您的测试中,您可以创建一个模拟 Timer 对象并在您创建类实例时传递它。

public class Authentication {
    private Timer timer;

    public Authentication(Timer timer){
        this.timer = timer;
        // constructor
    }

    public void authenticate(){
        // Initialize timer in this method
        timer = new RouterTimer(FAKE_PARAM);
        testingMethod();
    }

    @VisibleForTesting
    void testingMethod(){
        timer.method();
        // other stuff
    }
}

In the test, create mock timer using Mockito and pass it via constructor在测试中,使用 Mockito 创建模拟计时器并通过构造函数传递它

Timer mockTimer = Mockito.mock(Timer.class);
Authentication auth = new Authentication(mockTimer);

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

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