PowerMock.createPartialMock doesn't initialize object correctly

2,698 views
Skip to first unread message

Jimi

unread,
Feb 4, 2010, 9:41:52 AM2/4/10
to PowerMock
Hi,

During some refactoring of one of my classes I noticed that a unit
test suddenly started to fail. The change I made was to make a static
log4j Logger field into a instance field. The test failed with a NPE
on the first line where I used the log field, and when I did a simple
System.out.println("log: " + log); just before it printet "log: null".

I noticed that the test case that failed was the only test where I
used PowerMock.createPartialMock on my class under test. It seemed
that this partial mock didn't initiate the class properly.

I have been able to recreate this bug using this very simple java
class and test class (see code below). The test "testRegualFoo" works
just fine, and as a side note I notice that I get a "foo: bar"
printout in the console. The other two tests however, fails. The test
"testPartialMockedFooWithExpectedStringInput" gives me this assertion
error:

Unexpected method call doNothing(null):
doNothing("bar"): expected: 1, actual: 0

thus indicating that the variable foo is infact null. Also, there is
no printout of the foo variable, indicating that the constructor is
not run.

The test "testPartialMockedFooWithAnythingAsExpectedInput" doesn't
care of the value of the parameter to the doNothing-method, thus
making the test go just a little bit longer. However it fails with a
NPE when it tries to do "return foo.toUpperCase();" since foo is null.

This can surely not be the expected behaivor, right? Is this a known
bug? Or am I doing something wrong? I have read the documentation and
can't see that I have missed some important code.

Any help would be appreciated. I use Eclipse and PowerMock 1.3.5.

Regards
/Jimi

--- Start of Foo.java ------
public class Foo {

private String foo = "bar";

public Foo() {
System.out.println("foo: " + foo);
}

public String doSomething() {
doNothing(foo);
return foo.toUpperCase();
}

private void doNothing(String string) {

}
}
--- End of Foo.java ------


--- Start of TestFoo.java ------
import static org.junit.Assert.assertEquals;
import static org.powermock.api.easymock.PowerMock.expectPrivate;
import static org.powermock.api.easymock.PowerMock.replay;
import static org.powermock.api.easymock.PowerMock.verify;

import org.easymock.EasyMock;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.api.easymock.PowerMock;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest( { Foo.class })
public class TestFoo {

@Test
public void testRegualFoo() throws Exception {
Foo foo = new Foo();
assertEquals("BAR", foo.doSomething());
}

@Test
public void testPartialMockedFooWithExpectedStringInput() throws
Exception {
Foo partialMockedFoo = PowerMock.createPartialMock(Foo.class,
"doNothing");
expectPrivate(partialMockedFoo, "doNothing", "bar");
replay(partialMockedFoo);
assertEquals("BAR", partialMockedFoo.doSomething());
verify(partialMockedFoo);
}

@Test
public void testPartialMockedFooWithAnythingAsExpectedInput() throws
Exception {
Foo partialMockedFoo = PowerMock.createPartialMock(Foo.class,
"doNothing");
expectPrivate(partialMockedFoo, "doNothing", EasyMock.anyObject());
replay(partialMockedFoo);
assertEquals("BAR", partialMockedFoo.doSomething());
verify(partialMockedFoo);
}
}

--- End of TestFoo.java ------

Johan Haleby

unread,
Feb 4, 2010, 11:21:57 AM2/4/10
to powe...@googlegroups.com
Hi, 

This is the expected behavior, createPartialMock doesn't invoke the constructor by default. You should use "createPartialMock(Class<T> type, String[] methodNames, Object... constructorArguments) " to invoke a constructor when doing partial mocking with the EasyMock API. If you need to invoke a default constructor you should use "createPartialMockAndInvokeDefaultConstructor(Class<T> type, String... methodNames)". 

/Johan



--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To post to this group, send email to powe...@googlegroups.com.
To unsubscribe from this group, send email to powermock+...@googlegroups.com.
For more options, visit this group at http://groups.google.com/group/powermock?hl=en.


Jimi

unread,
Feb 4, 2010, 11:32:54 AM2/4/10
to PowerMock
Thank you, Johan! It worked like a charm.

But I find it a bit strange that the documentation didn't mention this
method at all. It only talks about the method createPartialMock. I
would think that behaivor of
createPartialMockAndInvokeDefaultConstructor is what most people would
expect when doing a partial mock. The way I see it, a partial mock
only mocks the methods that I tell it to mock. All other behaivor
should be exactly as for the class the mock is based on. But maybe
that's just me.

/Jimi

On 4 Feb, 17:21, Johan Haleby <johan.hal...@gmail.com> wrote:
> Hi,
>
> This is the expected behavior, createPartialMock doesn't invoke the
> constructor by default. You should use "createPartialMock(Class<T> type,
> String[] methodNames, Object... constructorArguments) " to invoke a
> constructor when doing partial mocking with the EasyMock API. If you need to
> invoke a default constructor you should use
> "createPartialMockAndInvokeDefaultConstructor(Class<T> type, String...
> methodNames)".
>
> /Johan
>

> > powermock+...@googlegroups.com<powermock%2Bunsu...@googlegroups.com>

Johan Haleby

unread,
Feb 4, 2010, 11:42:04 AM2/4/10
to powe...@googlegroups.com
If we would be designing the API today we would have done things much differently. The reason for not invoking the constructor by default is that this is the way EasyMock does it. We want to be as close as EasyMock as possible. I know EasyMock class extension has a new API for doing partial mocking since version 2.5 but I haven't look into it much and I don't have time to port it to PowerMock right now. If you'd like to help out by improving the documentation or code just send as patch.

/Johan


To unsubscribe from this group, send email to powermock+...@googlegroups.com.

Jimi

unread,
Feb 4, 2010, 1:14:30 PM2/4/10
to PowerMock
Ok, that makes perfect sense. To be honest I still haven't figured out
the relationship between PowerMock, EasyMock and Mockito.

Regarding the documentation, I have now added a comment on the
MockPartial page describing this. Hopefully it will help someone out.

/Jimi

On 4 Feb, 17:42, Johan Haleby <johan.hal...@gmail.com> wrote:
> If we would be designing the API today we would have done things much
> differently. The reason for not invoking the constructor by default is that
> this is the way EasyMock does it. We want to be as close as EasyMock as
> possible. I know EasyMock class extension has a new API for doing partial
> mocking since version 2.5 but I haven't look into it much and I don't have
> time to port it to PowerMock right now. If you'd like to help out by
> improving the documentation or code just send as patch.
>
> /Johan
>

> > <powermock%2Bunsu...@googlegroups.com<powermock%252Buns...@googlegroups.com>

Johan Haleby

unread,
Feb 5, 2010, 2:28:21 AM2/5/10
to powe...@googlegroups.com
Thanks :)

To unsubscribe from this group, send email to powermock+...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages