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

Viewed 198

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().

I'm writing unit test for testingMethod(), but the tests failed because the timer is null and calling the method() will throw an 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().

How do I mock or do something else in this case?

3 Answers

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.

In your test, you can create a mock Timer object and pass it when you create the class instance.

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

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