Eric B.
Eric B.

Reputation: 24411

How to use Mockito to test SOAP messages?

I'm fairly new to Mockito, and figured I would try to use it to test a SOAP Handler. However, this is turning out to be a much more painful than I would have expected/desired.

I'm looking to validate that my handler is able to extract the messageID in the header of a SOAPMessage. However, from the handler, the only way to get to the header is via the context/message/part/envelope/header. Using Mockito my solution was to mock my SOAPMessage, meant creating each individual object, and stubbing the method.

I can only imagine that there is an easier/cleaner way of accomplishing this:

@RunWith(MockitoJUnitRunner.class)
public class UUIDHandlerTest {

    @Mock private SOAPMessage message;
    @Mock private SOAPEnvelope envelope;
    @Mock private SOAPHeader header;
    @Mock private SOAPPart part;

    @Mock
    private SOAPMessageContext context;

    @Before
    public void setup() throws SOAPException{
        when( context.getMessage()).thenReturn(message);
        when( message.getSOAPPart()).thenReturn(part);
        when( part.getEnvelope()).thenReturn(envelope);
        when( envelope.getHeader()).thenReturn(header);
    }


    @Test
    public void testHandleInboundMessage() {
        when( context.get(SOAPMessageContext.MESSAGE_OUTBOUND_PROPERTY)).thenReturn(false);

        when(header.getElementsByTagName(anyString())).thenAnswer(new Answer<NodeList>() {
            /* (non-Javadoc)
             * @see org.mockito.stubbing.Answer#answer(org.mockito.invocation.InvocationOnMock)
             */
            @Override
            public NodeList answer(InvocationOnMock invocation) throws Throwable {
                DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
                DocumentBuilder db = dbf.newDocumentBuilder();
                Document doc = db.parse(new ByteArrayInputStream(new String("<wsa:MessageID>messageId</wsa:MessageID>").getBytes()));

                // TODO Auto-generated method stub
                return doc.getElementsByTagName("wsa:MessageID");
            }

        });


        // call the test class
        new UUIDHandler().handleMessage(context);

        // check the MDC value
        assertEquals("messageId", MDC.get(LoggerConstants.DC_PROPERTY_MESSAGE_ID));
    }
}

Like I said, it works, but it looks like a very ugly/heavy weight solution.

Is there anyway to do this easier/cleaner?

Thanks!

Eric

Upvotes: 8

Views: 20972

Answers (3)

ThomasRS
ThomasRS

Reputation: 8287

A bit late here, but I prefer spawning a working Endpoint which proxies a mockito mock. This lets me test the whole stack, including interceptors and/or handlers, which should be helpful for your use-case.

I've put up a simple JUnit Rule which simplifies things somewhat here. The resulting test-cases should be small and clean. I recommend loading test XML responses directly from XML files, because that is faster and more simple to maintain.

Upvotes: 1

time4tea
time4tea

Reputation: 2197

Don't mock things like this.

Listen to the code... its telling you that this is not the right way to do it.

Rather, just create a (real) message that has some known data in it, and assert that your code does the right stuff with it.

e.g.

MessageIdExtractor extractor = new MessageIdExtractor(); // <- class you are testing

String expectedMessageId = "xxxxxx";

Message m = new SOAPMessage( ).setMessageId(expectedMessageId);

assertThat(extractor.extractIdFrom(m), equalTo(expectedMessageId));

Upvotes: 0

Thomas
Thomas

Reputation: 759

    SOAPMessageContext context = 
            mock(SOAPMessageContext.class, RETURNS_DEEP_STUBS);
    when(context.getMessage().getSOAPPart().getEnvelope().
            getHeader().getElementsByTagName(anyString())).
            then(...);

Please also pay attention to the notes on using deep stubs in the mockito documentation. http://docs.mockito.googlecode.com/hg/org/mockito/Mockito.html#RETURNS_DEEP_STUBS

Annotation style:

    @Mock(answer = Answers.RETURNS_DEEP_STUBS) SOAPMessageContext context;

Upvotes: 4

Related Questions