mock a final static inner class

5,022 views
Skip to first unread message

unidever

unread,
Mar 15, 2012, 2:33:51 PM3/15/12
to PowerMock
So I am posting this to see if anyone has suggestions or a solution to
make this happen. I am writing the UT for a class that makes use of a
3rd party lib which I have no source for. It is a bit odd from what I
can tell it's decleration must be something like this.

public final class Subscription {
public static class Builder {
public Builder(String string) {

}
public Subscription build() {
return new Subscription();
}
}
public String getMessage() {
return "for fun";
}
}

So inside my class under test, EventHandler I have:

public class EventHandler {
@Inject
SomePojoDAO somePojoDAO

handleEvent(){
Subscription subscription = new
Subscription.Builder("event").build();
String s = subscription.getMessage();
somePojoDAO.save(new SomePojo(s));
}
}

@RunWith(PowerMockRunner.class)
@PrepareForTest(EventHandler.class)
public class EventHandler_UT {
@Mock
SomePojoDAO mockSomePojoDAO;

@InjectMocks
EventHandler myEventHandler=new EventHandler();

@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}

@Test
public void testHandleEvent {
//I want to mock out Subscription and have that mock be
// be returned as a call to the build method
when(mockSubscription.getMessage).thenReturn("for fun");
myEventHandler.handleEvent()
verify(mockSomePojoDAO).save("for fun");
}
}

So it's a new call to a final class which has an innter static class
that has a public method. For clarity I broke up the build call with a
middle man variable.
Subscription.Builder middleman = new Subscription.Builder("event");
Subscription subscription = middleman.build();
Any suggestions?

Mike

Johan Haleby

unread,
Mar 16, 2012, 3:10:40 AM3/16/12
to powe...@googlegroups.com
Hi, 

First of all I would take a step back and wonder if it's really required to mock the third-party class. Is there anything in particular that prevents you from doing state verification instead of behavior verification (http://martinfowler.com/articles/mocksArentStubs.html) in this case? Perhaps you should add an anti-corruption layer and follow the "don't mock types you don't own" principle? There are lots of design considerations to think about :)

Looking briefly at your test code I think you have two potential problems.
  1. I'm not really sure why you prepare the EventHandler class. Is it because you want to mock new instance creation of the Subscription class? (in that case it's correct :))
  2. Using "MockitoAnnotations.initMocks(this);" will override the mocks created by PowerMock. PowerMock should inject mocks annotated with @Mock automatically when using the PowerMock Junit runner.
I think the easiest way for you is to stub the "getMessage" method using the stubbing API:
  1. Use @PrepareForTest(Subscription.class)
  2. In your test method write:
    stub(method(Subscription.class, "getMessage")).toReturn("for fun");
The drawback is the the call to "getMessage" is not type safe but since you have a third-party lib it may not be subject to change anyway. 

Regards,
/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.


unidever

unread,
Mar 16, 2012, 3:10:50 PM3/16/12
to PowerMock
Johan,
thanks for all the suggestion and info. To give a little background
this class had zero test coverage and the Subscription class was a
subscriber to JMS messaging queue so for it to function, I'd need the
running message broker and this message handler would need to be
deployed on my J2EE container so I thought I'd mock it. Basicly it
provides a payload from the queue (large XML string) to a xml parser
and then the code converts it into the POJO to be persisted. So the
build method needs to return a large xml charachter string. I got this
to work and this is what I did:

@RunWith(PowerMockRunner.class)
@PrepareForTest({EventHandler.class,Subscription.class})
public class EventHandler_UT {
@Mock
EssDataDAO mockEssDataDAO;
@Mock
Builder mockBuilder;
@InjectMocks
EventHandler myEventHandler=new EventHandler();

@Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
}
@Test
public void testHandleEventHappyPath() throws Exception{

whenNew(Subscription.Builder.class).withArguments(anyString()).thenReturn(mockBuilder);
Subscription mockSubscription = createMock(Subscription.class);
when(mockBuilder.build()).thenReturn(mockSubscription);
expect(mockSubscription.getMessage()).andReturn(getPayload());
replay(mockSubscription);
myEventHandler.handleEvent("any string");
verify(mockEssDataDAO,times(2)).save((EssData)anyObject());
}
}

This is just a very abbreviated version of everything but I show
new'ing the inner static class, which was nothing tricky but mocking
the final class which had the method getMessage is where the xml
payload would be. I did not know I didn't need
MockitoAnnotations.initMocks(this). At first I was confused because
the EventHandler had no setter for the DAO nor a constructor passing
it in. But marking mockDAO with @Mock works. Also, I did not know
about the supress method. All good tips thank you. Interestingly
Builder is a static class but build requires nothing special for it's
call to return something. The call on getMessage does require some
extra work though being that I was mocking the final class
Subscription.

Mike



Johan Haleby

unread,
Mar 18, 2012, 2:14:42 PM3/18/12
to powe...@googlegroups.com
Glad you got it working and thanks for sharing!

Regards,
/Johan

Hema Priya

unread,
Feb 23, 2019, 10:36:31 AM2/23/19
to PowerMock
Thanks for the post Mike , now i know how to write unit tests for inner class methods.
Reply all
Reply to author
Forward
0 new messages