PowerMockito testing private constructors

2,739 views
Skip to first unread message

johanmartinsson

unread,
Nov 11, 2009, 1:35:27 PM11/11/09
to PowerMock
I have a problem similar to http://groups.google.com/group/powermock/t/95f6c783f90fe843

I want to test a singleton lazy initialization.

Here's my singleton
public class BadInitializer {
private static BadInitializer instance;
public static BadInitializer getInstance() {
if (instance == null) {
instance = new BadInitializer();
}
return instance;
}

private BadInitializer() {
System.out.println("Initialized on : " + new Date());
}
}

I want to test that my object is only initialized once, which I doubt
for concurrent calls to getInstance()
@RunWith(PowerMockRunner.class)
@PrepareForTest( BadInitializer.class )
public class TestBadInitializer {

@Test
public void testOnlyInitializedOnce() throws Exception {
BadInitializer.getInstance();
verifyNew(BadInitializer.class).withNoArguments();
}
}
I expect this code to succeed, and then fail when I replace
BadInitializer.getInstance() with some kind of
callGetInstanceWithConcurrentThreads() implementation.

However I get an error stating "IllegalArgumentException: A
constructor invocation in class BadInitializer was unexpected."
as if I was supposed to configure my mock with a EasyMock-like
expectation.

* First question : Am I supposed to configure one? *

Anyway I tried to mimick Johan Haleby's file creation example (http://
blog.jayway.com/2009/10/28/untestable-code-with-mockito-and-
powermock/) with :

public void testOnlyInitializedOnce() throws Exception {
whenNew(BadInitializer.class).withNoArguments().thenCallRealMethod
();
BadInitializer.getInstance();
verifyNew(BadInitializer.class).withNoArguments();
}

But then I get java.lang.ArrayIndexOutOfBoundsException: 0
at
org.powermock.api.mockito.internal.invocationcontrol.MockitoNewInvocationControl.invoke
(MockitoNewInvocationControl.java:53)

What am I missing here? (This error actually originates some
instrumented code in the mockito API when MethodProxy.invokeSuper())


I got things working with the following code
public void testOnlyInitializedOnce() throws Exception {
BadInitializer mock = mock(BadInitializer.class);
whenNew(BadInitializer.class).withNoArguments().thenReturn(mock);
BadInitializer.getInstance();
verifyNew(BadInitializer.class).withNoArguments();
}

But that's not quite what I wan because the real constructor isn't
called and thus I never expose the bug

* Second question : How do I expose the fact that my constructor could
be called several times with powermockito *

Thanks
Johan




Johan Haleby

unread,
Nov 12, 2009, 3:02:59 AM11/12/09
to powe...@googlegroups.com
Hi,

Thanks for your thorough explanation. I will try this as soon as I get a chance, it will probably be tomorrow evening  or some time during this weekend.

How ever I think you should test this without mocking at all. Just invoke the method twice and make sure that you get the same object back, no need for mocking afaict. You can also verify that the BadInitializer instance field is null by default using Whitebox if you want to do that. Testing for thread-safetly is tricker (but doable).

/Johan

johanmartinsson

unread,
Nov 12, 2009, 5:23:23 PM11/12/09
to PowerMock
You're perfectly right, I overlooked the simple solution (or one of
them anyway).

So that solved my problem. But having spent some time to get powermock
working for my example I'd still appreciate if you have the
oppurtunity to run my example.

Anyway, I'll post the working test code even if it has nothing to do
with PowerMock :
public class TestBadInitializer {
private Set<Object> numberOfObjects;
private static final int nbThreads = 10;

@Test
public void testOnlyInitializedOnce() throws Exception {
doParallellCalls();
assertEquals("More than one object was returned from the getInstance
call",
1, numberOfObjects.size());
}

private class Client extends Thread {
public void run() {
numberOfObjects.add(BadInitializer.getInstance());
}
}

private void doParallellCalls() throws InterruptedException {
Client[] clients = new Client[nbThreads];
for (int i = 0; i < nbThreads; i++) {
clients[i] = new Client();
}
for (Client client : clients) {
client.start();
}
for (Client client : clients) {
client.join();
}
}

@Before
public void startUp() {
numberOfObjects = Collections.newSetFromMap(new HashMap<Object,
Boolean>(nbThreads));
}

}

On 12 nov, 09:02, Johan Haleby <johan.hal...@gmail.com> wrote:
> Hi,
>
> Thanks for your thorough explanation. I will try this as soon as I get a
> chance, it will probably be tomorrow evening  or some time during this
> weekend.
>
> How ever I think you should test this without mocking at all. Just invoke
> the method twice and make sure that you get the same object back, no need
> for mocking afaict. You can also verify that the BadInitializer instance
> field is null by default using Whitebox if you want to do that. Testing for
> thread-safetly is tricker (but doable).
>
> /Johan
>
> On Wed, Nov 11, 2009 at 7:35 PM, johanmartinsson <martinsson.jo...@gmail.com
> > powermock/<http://blog.jayway.com/2009/10/28/untestable-code-with-mockito-and-%0...>)
Reply all
Reply to author
Forward
0 new messages