0

The solution proposed as a duplicate is not a PowerMockito solution and as a consequence does not answer this question. Further, this question IS answered legitimately below.

IDK if this is a duplicate or not but I sure can't find the item in question if it is. I keep expecting this to be really simple, since it is pretty simple with reflection but I'd rather do it using the right tools.

Clarification: Legacy code. No getters / setters.

Is it correct to use Whitebox for this? I thought it was "Off Limits" i.e. part of the internal API? ...or was that strictly Mockito?

user447607
  • 5,149
  • 13
  • 33
  • 55
  • 1
    Private code should not be mocked. Having to mock private dependencies is a code smell. Code may need refactoring, legacy or not. – Nkosi Feb 08 '18 at 17:57
  • Which doesn't mean you get a choice. It's not that I can't. It's that they won't pay for it and if I do that instead of what I'm supposed to be doing bad stuff will happen to me. It's also not that I can't do it just this once, either but if I start doing that as a policy I'll have to rewrite the whole app. So my policy is that I can lead a horse to water but I can't make management pay for good coding practices. – user447607 Feb 08 '18 at 18:07
  • 1
    See `Whitebox.setInternalState(...)`. Make sure it's understood the budget is causing technical debt. – Andrew S Feb 08 '18 at 18:14
  • That point has been made so often that speaking of it is now taboo. – user447607 Feb 08 '18 at 18:15
  • Make Whitebox an answer and I'll select. – user447607 Feb 08 '18 at 18:16

1 Answers1

6

See Whitebox.setInternalState(...).

For example - given class A which needs to be tested:

public class A {
    private B b;

    public A() {
        b = new B();
    }

    public void doSomething() {
        b.doSomething();
    }

}

which has a private instance of B:

public class B {

    public void doSomething() {
        // some long running, resource intensive process...
        System.out.println("Real B.doSomething() was invoked.");
    }

}

then Whitebox can be used to set the private state of A so it can be tested:

import static org.mockito.Mockito.doNothing;
import static org.mockito.Mockito.verify;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.runners.MockitoJUnitRunner;
import org.powermock.reflect.Whitebox;

@RunWith(MockitoJUnitRunner.class)
public class ATest {

    @Mock
    private B b;

    private A a;

    @Before
    public void prepareTest() {
        doNothing().when(b).doSomething();

        a = new A();
        Whitebox.setInternalState(a, B.class, b);
    }

    @Test
    public void doSomething() {
        a.doSomething();
        verify(b).doSomething();
    }

}
Andrew S
  • 2,509
  • 1
  • 12
  • 14