-
Notifications
You must be signed in to change notification settings - Fork 138
Migration guide: Citrus 2.x to 3.x
Our work on Citrus 3.0 has begun and this page is here to collect migration steps that users need to perform when upgrading from former Citrus versions.
- Citrus Settings
- Channel endpoints
- Test Reporter
- Cucumber BDD
- Sleep action
- Hamcrest Matcher
- Endpoint adapter configuration
- Moved classes
Default settings and constants have been moved to a new utility class named CitrusSettings
.
Citrus.DEFAULT_MESSAGE_TYPE
CitrusSettings.DEFAULT_MESSAGE_TYPE
The Spring integration message channel endpoint is no longer the default endpoint implementation used by server components. The new default is the DirectEndpoint.
Because of this we have moved the Spring integration message channel endpoint implementation from citrus-core
to a separate module called citrus-spring-integration
.
<dependency>
<groupId>com.consol.citrus</groupId>
<artifactId>citrus-spring-integration</artifactId>
<version>${citrus.version}</version>
</dependency>
When you keep using citrus-core
as dependency in your project it already includes the new citrus-spring-integration
module as dependency so you do not need to adjust anything here.
In case you are using the XML Spring bean configuration in Citrus you have to change the XML namespaces though.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:citrus="http://www.citrusframework.org/schema/config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config.xsd">
<citrus:channel-endpoint id="fooEndpoint"
channel="foo"/>
<citrus:channel-sync-endpoint id="fooSyncEndpoint"
channel="foo"/>
<citrus:channel id="foo" capacity="5"/>
</beans>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:citrus="http://www.citrusframework.org/schema/config"
xmlns:citrus-si="http://www.citrusframework.org/schema/spring-integration/config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config.xsd
http://www.citrusframework.org/schema/spring-integration/config http://www.citrusframework.org/schema/spring-integration/config/citrus-spring-integration-config.xsd">
<citrus-si:channel-endpoint id="fooEndpoint"
channel="foo"/>
<citrus-si:channel-sync-endpoint id="fooSyncEndpoint"
channel="foo"/>
<citrus-si:channel id="foo" capacity="5"/>
</beans>
Notice that the components have been moved out of the default namespace xmlns:citrus="http://www.citrusframework.org/schema/config"
to a new one xmlns:citrus-si="http://www.citrusframework.org/schema/spring-integration/config"
.
As an alternative you can also use the new direct endpoint implementation that is now located in the default Citrus configuration namespace.
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:citrus="http://www.citrusframework.org/schema/config"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.citrusframework.org/schema/config http://www.citrusframework.org/schema/config/citrus-config.xsd">
<citrus:direct-endpoint id="fooEndpoint"
queue="foo"/>
<citrus:direct-sync-endpoint id="fooSyncEndpoint"
queue="foo"/>
<citrus:queue id="foo"/>
</beans>
The test reporter interface has changed in its signature and way of working.
public interface TestReporter {
/**
* Test reporter generates a report for several test suite instances.
*/
void generateTestResults();
/**
* Dismiss previous test results for next test run.
*/
void clearTestResults();
}
public interface TestReporter {
/**
* Test reporter generates a report for several test suite instances.
*/
void generateReport(TestResults testResults);
}
In former Citrus versions the reporter had to also implement TestListener
, TestActionListener
and TestSuiteListener
interfaces in order to collect the test results on its own. This resulted in all reporters actually doing the same to get all test results for report generation.
We have refactored this so the reporter is provided with the test results when generating the report. The test results are now collected in a single central place.
In case you have a custom test reporter you may need to adjust to this new API.
We have updated from Cucumber 3.x to 5.x and there are some changes due to this major update. You need to change the cucumber.properties
to select the new object factory implementation:
cucumber.api.java.ObjectFactory=cucumber.runtime.java.CitrusObjectFactory
cucumber.object-factory=com.consol.citrus.cucumber.backend.CitrusObjectFactory
Also all custom steps need to use the new TestCaseRunner
API:
public class TodoSteps {
@CitrusResource
private TestRunner runner;
@Given("^Todo list is empty$")
public void empty_todos() {
runner.http(httpActionBuilder -> httpActionBuilder
.client("todoListClient")
.send()
.delete("/api/todolist"));
runner.http(httpActionBuilder -> httpActionBuilder
.client("todoListClient")
.receive()
.response(HttpStatus.OK));
}
}
public class TodoSteps {
@CitrusResource
private TestCaseRunner runner;
@Given("^Todo list is empty$")
public void empty_todos() {
runner.given(http()
.client("todoListClient")
.send()
.delete("/api/todolist"));
runner.then(http()
.client("todoListClient")
.receive()
.response(HttpStatus.OK));
}
}
The sleep
test action builder in Java DSL has changed. In former versions the type (Long or Double) of the given method parameter specified the time in milliseconds or seconds.
sleep(500L); //500 milliseconds
sleep(2.5D); //2.5 seconds
In Citrus 3.0 you specify the amount of time to sleep with separate methods.
sleep().milliseconds(500L);
sleep().seconds(2.5D);
sleep().time(Duration.ofMillis(5000));
sleep().time("${days}", TimeUnit.DAYS);
In former Citrus versions you were able to use Hamcrest matchers directly as condition value in an iterating container.
import static org.hamcrest.Matchers.lessThanOrEqualTo;
@Test
@CitrusTest
public void testHamcrestCondition() {
iterate()
.condition(lessThanOrEqualTo(5))
.actions(
createVariable("todoId", "citrus:randomUUID()"),
createVariable("todoName", "todo_${i}"),
createVariable("todoDescription", "Description: ${todoName}")
);
}
With Citrus 3.0 the dependency to Hamcrest features is optional so you can also choose another implementation (e.g. AssertJ). This leads us to changing the supported condition value that you can pass into the container. There is a new ConditionExpression
wrapper that holds the actual matcher implementation.
import static com.consol.citrus.container.HamcrestConditionExpression.assertThat;
import static org.hamcrest.Matchers.lessThanOrEqualTo;
@Test
@CitrusTest
public void testHamcrestCondition() {
iterate()
.condition(assertThat(lessThanOrEqualTo(5)))
.actions(
createVariable("todoId", "citrus:randomUUID()"),
createVariable("todoName", "todo_${i}"),
createVariable("todoDescription", "Description: ${todoName}")
);
}
Endpoint adapters are commonly used in server components to handle incoming requests and provide proper response messages. Each server component has an endpoint adapter configured by default. In case you want to overwrite the endpoint adapter you can do this in a Spring bean configuration for instance.
@Bean
public EndpointAdapter todoResponseAdapter() {
StaticResponseEndpointAdapter endpointAdapter = new StaticResponseEndpointAdapter();
endpointAdapter.setMessagePayload("{" +
"\"id\": \"${todoId}\"," +
"\"title\": \"${todoName}\"," +
"\"description\": \"${todoDescription}\"," +
"\"done\": false" +
"}");
return endpointAdapter;
}
In former Citrus versions the endpoint adapter has had some autowired components like the TestContextFactory
. As we have moved Spring autowiring to factory beans in a separate module you can no longer use variable support in the endpoint adapter as shown above with ${todoId}
in the response payload data. In order to add support for the variables we need to explicitly set the TestContextFactory
:
@Bean
public EndpointAdapter todoResponseAdapter(TestContextFactory contextFactory) {
StaticResponseEndpointAdapter endpointAdapter = new StaticResponseEndpointAdapter();
endpointAdapter.setMessagePayload("{" +
"\"id\": \"${todoId}\"," +
"\"title\": \"${todoName}\"," +
"\"description\": \"${todoDescription}\"," +
"\"done\": false" +
"}");
endpointAdapter.setTestContextFactory(contextFactory);
return endpointAdapter;
}
You simply need to set the TestContextFactory
on the endpoint adapter. As an alternative you can use the factory bean for the endpoint adapter where autowiring of Spring beans is enabled as it was done before in previous Citrus versions.
@Bean
public StaticResponseEndpointAdapterFactory todoResponseAdapter() {
StaticResponseEndpointAdapterFactory endpointAdapterFactory = new StaticResponseEndpointAdapterFactory();
endpointAdapterFactory.setMessagePayload("{" +
"\"id\": \"${todoId}\"," +
"\"title\": \"${todoName}\"," +
"\"description\": \"${todoDescription}\"," +
"\"done\": false" +
"}");
return endpointAdapterFactory;
}
Class | Description | From | To |
---|---|---|---|
Functions | Citrus functions catalog class combining all available default functions to be called in Java DSL | com.consol.citrus.dsl.functions | com.consol.citrus.functions |