• No results found

Testing the transformer

In document Spring Integration in Action (Page 119-122)

Getting down to business

5.1 Domain-driven transformation

5.1.4 Testing the transformer

Now you can write a JUnit test class that sends a Message to the flightDelayInput channel. That message’s payload should be a string with the expected format. If all goes well, the delayEvents channel should have a message enqueued whose payload is actually a FlightDelayEvent instance. The real test is whether that event has an estimatedDeparture property that correctly reflects the delay. The following listing provides the full test class example.

package siia.business; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.Message; import org.springframework.integration.MessageChannel; import org.springframework.integration.core.PollableChannel; import org.springframework.integration.support.MessageBuilder; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import java.util.Date;

import static org.junit.Assert.assertEquals; import static org.junit.Assert.assertNotNull; @ContextConfiguration

@RunWith(SpringJUnit4ClassRunner.class)

public class FlightDelayTransformerIntegrationTests { @Autowired

private MessageChannel flightDelayInput; @Autowired

private PollableChannel delayEvents; @Test

public void verifyDelay() {

Listing 5.1 Running a test using @Test

input-channels are created implicitly if not already defined within the context

89

Domain-driven transformation

long currentTime = System.currentTimeMillis(); Message<String> message =

MessageBuilder.withPayload("SI77+0130").build(); flightDelayInput.send(message);

Message<?> transformed = delayEvents.receive(0); assertNotNull(transformed);

Object payload = transformed.getPayload(); assertNotNull(payload);

assertEquals(FlightDelayEvent.class, payload.getClass()); Date estimatedDeparture =

((FlightDelayEvent) payload).getEstimatedDeparture(); long secondsFor1hr30min = 90 * 60;

long delay = estimatedDeparture.getTime() - currentTime; assertEquals(secondsFor1hr30min, delay / 1000);

} }

As you can see, the test confirms that the estimated departure time has been adjusted according to the delay event. The test even provides a few null checks and verifies that the payload type is correct. Those assertions can be helpful because the exact line of the test failure will indicate what the problem was. You don’t need to worry too much about the details of this test logic. The main thing to learn from all of this is how to create a simple integration test for a message endpoint that involves sending and receiving messages across message channels. In case you’re not familiar with Spring’s integration testing support, we provide a quick overview by describing the test class in listing 5.1. If you want to delve into more detail, refer to the Spring Framework refer- ence manual’s testing chapter.

The @Test annotation is a JUnit 4 annotation and indicates that a particular method provides a test case. This is a nice improvement over the JUnit 3 style, which required methods to begin with test. Another nice change in JUnit 4 is that it’s no longer necessary to extend a TestCase superclass as provided by the framework. Instead, the default test runner strategy knows how to detect the @Test annotations. Luckily, it’s still possible to extend the testing framework by providing a customized implementation of the test runner. This is how Spring provides its integration testing support for a JUnit 4 environment. In listing 5.1, you can see that Spring’s test runner class is provided within JUnit’s @RunWith annotation.

The other class-level annotation, @ContextConfiguration, is defined by Spring’s integration test framework, which directs Spring’s test runner to locate a configura- tion file with the same name as the current test class but with a -context.xml suffix. For example, the configuration file to be used in conjunction with the test class in listing 5.1 would be named FlightDelayTransformerIntegrationTests-context.xml, which should be located in the same package as the test class. That pretty much covers the testing support for this example. The @Autowired annotation is standard Spring, and the field name is used to drive resolution based on bean names because a resolu- tion based on type alone would lead to ambiguities in this case.

90 CHAPTER 5 Getting down to business

The previous sections explained how to marshal and unmarshal objects to and from different formats. You also learned how to test these applications using Spring’s test context support. The requirement to convert a simple unique identifier to a fully populated instance of a domain object is a common one, but message transformers can address many other common requirements. Let’s take a quick look at a few other types of transformation that rely closely on the code from the particular domain model of an application.

5.1.5 Content enricher

Another common requirement is to add content to an existing domain object by invoking a business service. For example, for the flight booking use case, you might need to add the email address of a given passenger. Imagine that you could uniquely identify the passenger on the basis of a frequent flyer program number and also look up the email address from the frequent flyer information service. An implementation of this logic in a transformer could be considered a content enricher. The email address is the enriched content being added to the payload of a message that didn’t yet include that information.

In fact, if a user is enrolled in the frequent flyer program, you may be able to add much more information beyond the email address. The user’s profile may contain preferences, such as meal type, and whether the passenger prefers aisle or window seating. The information would probably also include mileage credits and status.

The main point is that a Passenger instance may or may not contain all of this data. The airline doesn’t require enrollment in the frequent flyer program, so a mini- mal Passenger instance may contain only the person’s name and some form of official identification, such as a passport number, driver’s license number, or tax ID. The con- tent enricher in the following listing adds the extra information if available but other- wise passes on unaffected Passenger instances.

package siia.business;

import org.springframework.beans.factory.annotation.Autowired; import org.springframework.integration.annotation.MessageEndpoint; @MessageEndpoint

public class PassengerProfileEnricher {

private final FrequentFlyerService frequentFlyerService; @Autowired

public PassengerProfileEnricher(FrequentFlyerService ffService) { this.frequentFlyerService = ffService;

}

public Passenger addProfileIfAvailable(Passenger passenger) { String ffNumber = passenger.getFrequentFlyerNumber(); if (ffNumber != null) {

Profile profile =

91

In document Spring Integration in Action (Page 119-122)