Nathan Russell
Nathan Russell

Reputation: 3678

How to unit test Spring Integration flow - specifically http outbound gateway

I wonder if anyone can help - this has been driving me crazy for days!

I have a fairly simple Spring Integration file that I'd like to unit test. The SI uses an http outbound gateway, and I specifically want to unit test rather than integration test - I do not want to provide a mock http server using something like Spark or MockRestServiceServer.

My SI config looks like this:

<int:channel id="modifiedAttractionChannel" datatype="u.o.n.p.i.a.s.AttractionUuid">
    <int:interceptors>
        <int:wire-tap channel="attractionModifiedChannelLogging"/>
    </int:interceptors>
</int:channel>

<int-http:outbound-gateway
        id="serviceGateway" 
        request-channel="modifiedAttractionChannel"
        url="/attractions/{uuid}" 
        http-method="GET"
        expected-response-type="u.o.n.p.i.a.v.m.Attraction"
        charset="UTF-8"
        reply-timeout="${vader.reply.timeout}"
        request-factory="clientHttpRequestFactory"
        reply-channel="vaderAttractionChannel">
    <int-http:uri-variable name="uuid" expression="headers['#{T(u.o.n.p.i.a.s.AttractionsImportInitializer).HEADER_UUID}'].value" />
</int-http:outbound-gateway>

<int:channel id="attractionChannel" datatype="u.o.n.p.i.a.v.m.Attraction">
    <int:interceptors>
        <int:wire-tap channel="vaderAttractionChannelLogging"/>
    </int:interceptors>
</int:channel>

<int:logging-channel-adapter 
        id="attractionModifiedChannelLogging"
        expression="'attractionModifiedChannel: header=' + headers['#{T(u.o.n.p.i.a.s.AttractionsImportInitializer).HEADER_UUID}'].value + ', payload=' + payload" 
        level="INFO" />

<int:logging-channel-adapter 
        id="vaderAttractionChannelLogging" 
        expression="'attractionModifiedChannel: header=' + headers['#{T(u.o.n.p.i.a.s.AttractionsImportInitializer).HEADER_UUID}'].value + ', payload=' + payload" 
        level="INFO" />

I have written a unit test that wires up a basic spring context and am able to get the modifiedAttractionChannel and send an appropriately built Message with an AttractionUuid payload and header value.

My unit test can assert that the log message written to attractionModifiedChannelLogging is as I expect it (I created the AttractionUuid and Message, so I know the payload and header values)

What I now need to do is assert the value written to the vaderAttractionChannelLogging wiretap. IE. I need to assert a message with a given header value - no problem, I created the header value as part of the test - but also the payload.

In this case the payload is the output of the outbound gateway. Given that this is a unit test and I don't want any dependency on anything else, I have provided a mock ClientHttpRequestFactory which in turn provides a mock ClientHttpResponse via a mock ClientHttpRequest

This works great in that I can control the response body that the outbound gateway would otherwise receive. However, the RestTemplate calls its HttpRequestExecutingMessageHandler in order to convert the response body into an object via the MessageConverters

Whilst this works in respect of the execution of the SI flow, it means the instance of Attraction that is on the reply-channel vaderAttractionChannel is not in control of the test; and therefore I cannot make any assertions about it in respect of what gets logged on the vaderAttractionChannelLogging wiretap.

I think one way of addressing this is to be able to wire in a mock or stub MessageConvertor instead of the standard set that returns a fixed Attraction instance. But I can't for the life of me work out how to!

Note: The scenario above is a much simplified version of what I'm actually trying to do. I'm not really trying to write unit tests around logged values! I need to test the overall flow of my SI, and being able to control the instance of the Attraction that the outbound gateway returns is very much key to that.

Any help with this would be very much appreciated;
Cheers

Nathan

Upvotes: 2

Views: 1461

Answers (1)

Gary Russell
Gary Russell

Reputation: 174729

It's not clear what your issue is; "...the RestTemplate calls its HttpRequestExecutingMessageHandler..." - it's actually the other way around. If you really want to unit test the flow, you should provide a normal result from the mock that will be converted by the standard converters. If you really want to mock the conversion too, use the message-converters attribute.

Upvotes: 1

Related Questions