Mocking StringBuilder (system class) method toString() just doesn't work using powermock-easymock

2,473 views
Skip to first unread message

rfjaco...@att.net

unread,
Sep 5, 2015, 12:00:50 AM9/5/15
to PowerMock
I have done a thorough search through all of the PowerMock-EasyMock documentation, forums, etc. and have not found a definitive answer to my above-mentioned issue.

My current software: jdk1.7.0_55
                               powermock-easymock 1.6.0_full
                               EasyMock 3.2
                               javassist 3.19.0.GA

I have looked at the section in the documentation that describes mocking system classes, but this only shows how to mock system classes with static methods.

There is contradictory information in the forums and Google posts about mocking the toString() method; some saying it cannot be done for any object because javassist bypasses those calls.

Does anyone have the definitive answer on mocking toString(), specifically in class StringBuilder?

I have tried the following:

                String myExportFileName = "myExportFile";
                MemberModifier.stub(Whitebox.getMethod(StringBuilder.class, "toString")).toReturn(myExportFileName);

This returns the actual file name from the implementation instead of myExportFileName.

The documentation states that we cannot call methods in system classes in the same manner as we call them in user-defined classes, for example, the following would not be expected to work, and it doesn't:

StringBuilder sb = createMock(StringBuilder.class);
expect(sb.toString()).andStubReturn(myExportFileName);

Can anyone shed some light on this issue. There does not appear to be a definitive answer anywhere.

Thanks in advance for anyone's help.

- R Jacobsen

09/04/2015

Johan Haleby

unread,
Sep 5, 2015, 12:11:31 AM9/5/15
to powe...@googlegroups.com
Hi, 

First of all I really encourage you to find another way to test whatever it is you're trying to test. I would seriously recommend against mocking StringBuilder since I can't see when you would ever need to do such a thing. But you can:

public class SystemClassUser {
public StringBuilder newStringBuilder() {
return new StringBuilder();
}
}

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SystemClassUser.class })
public class SystemClassUserTest {
@Test
public void mockingStringBuilder() throws Exception {
// Given
final StringBuilder mock = mock(StringBuilder.class);
whenNew(StringBuilder.class).withNoArguments().thenReturn(mock);
when(mock.toString()).thenReturn("My toString");

// When
final StringBuilder actualStringBuilder = new SystemClassUser().newStringBuilder();
final String actualToString = actualStringBuilder.toString();


// Then
assertSame(mock, actualStringBuilder);
assertEquals("My toString", actualToString);
} }
Regards
/Johan


--
You received this message because you are subscribed to the Google Groups "PowerMock" group.
To unsubscribe from this group and stop receiving emails from it, send an email to powermock+...@googlegroups.com.
To post to this group, send email to powe...@googlegroups.com.
Visit this group at http://groups.google.com/group/powermock.
For more options, visit https://groups.google.com/d/optout.

rfjaco...@att.net

unread,
Sep 8, 2015, 11:48:38 PM9/8/15
to PowerMock
Hi Johan. Thank you for your response.
I agree that having the need to mock a system class method reveals a brittle design, however, this test is for a method that is part of proprietary, legacy code and sometimes legacy code does not lend itself well to doing good testing. The method under test uses StringBuilder to create a file name that contains a timestamp and then uses the toString() method to return the composite name as a new String. We have a number of situations where we create files with embedded time stamps in their names. Using powermock-easymock, it is not possible to set up a proper expect() call since we will never know the value of the time stamp used in the file name. So the logical approach will be to stub the method call and return a simple String value. If I change the method under test to use the StringBuilder substring(0) call (which is basically equivalent to the toString() call), my test works when I set up the stub as shown in my original post using "substring" instead of toString(). That's a bit of a hack which I would prefer to avoid since the toString() method would be the preferred approach. I see that your solution uses the mockito libraries; I will see if I can conjur up a working solution using the powermock-easymock libraries. Unfortunately, since the legacy code is not very elegant, I find it necessary to set up these kinds of tests.

Thanks again for your help.

/Robert
Reply all
Reply to author
Forward
0 new messages