/
How to write unit test?
How to write unit test?
Test classes hierarchy
- there is modul openhub-test that defines base classes supporting testing. Classes are defined in package org.openhubframework.openhub.test
- base class hierarchy
- classes overview:
- AbstractTest - main parent class for implementing unit tests
- defines Spring profile "test"
- references TestConfig that defines basic configuration for tests
- defines common handy methods
- AbstractDbTest - main parent class for writing tests with database
- extends AbstractTest
- defines Spring profile "h2" when H2DB is used for unit tests
- defines handy methods for working with DB
- ActiveRoutes - annotation that is used to declare which Camel route definitions should be active for specific test.
- ActiveRoutesCollector activates only routes which are defined by ActiveRoutes annotation
- AbstractTest - main parent class for implementing unit tests
How to set up tests for new module/project
define configuration specific for the module
@ComponentScan(basePackages = {"org.openhubframework.openhub.modules"}) @PropertySource(value = {"classpath:/config/application-test-default.properties"}) public class ExampleTestConfig { }
There is application-test-default.properties file in core module that contains default values of configuration parameters for unit tests.
define parent classes for unit tests without and with database
@ActiveRoutes(classes = ExceptionTranslationRoute.class) @ContextConfiguration(classes = ExampleTestConfig.class) @ActiveProfiles(profiles = ExampleProperties.EXAMPLE_PROFILE) public abstract class AbstractExampleModuleTest extends AbstractTest { }
@ActiveRoutes(classes = ExceptionTranslationRoute.class) @ContextConfiguration(classes = ExampleTestConfig.class) @ActiveProfiles(profiles = ExampleProperties.EXAMPLE_PROFILE) public abstract class AbstractExampleModulesDbTest extends AbstractDbTest { }
Implement unit tests
See Camel testing for more info how to write unit tests with Camel.
synchronnous routes don't need database => AbstractExampleModuleTest is suitable parent class
@ActiveRoutes(classes = SyncHelloRoute.class) public class SyncHelloRouteTest extends AbstractExampleModuleTest { @Produce(uri = TestWsUriBuilder.URI_WS_IN + "syncHelloRequest") private ProducerTemplate producer; @EndpointInject(uri = "mock:test") private MockEndpoint mock; /** * Checking successful calling. */ @Test public void testSyncHelloRoute() throws Exception { String xml = "<syncHelloRequest xmlns=\"http://openhubframework.org/ws/HelloService-v1\">" + " <name>Mr. Parker</name>" + "</syncHelloRequest>"; String output = producer.requestBody((Object)xml, String.class); SyncHelloResponse res = Tools.unmarshalFromXml(output, SyncHelloResponse.class); assertThat(res, notNullValue()); assertThat(res.getGreeting(), is("Hello Mr. Parker")); } }
asynchronnous routes save messages into dabatase therefore they need DB configuration => AbstractExampleModulesDbTest is suitable parent class
@ActiveRoutes(classes = AsyncHelloRoute.class) public class AsyncHelloRouteTest extends AbstractExampleModulesDbTest { private static final String REQ_XML = "<asyncHelloRequest xmlns=\"http://openhubframework.org/ws/HelloService-v1\">" + " <name>Mr. Parker</name>" + "</asyncHelloRequest>"; @Produce(uri = TestWsUriBuilder.URI_WS_IN + "asyncHelloRequest") private ProducerTemplate producer; @EndpointInject(uri = "mock:test") private MockEndpoint mock; @Test public void testRouteIn_responseOK() throws Exception { getCamelContext().getRouteDefinition(AsyncHelloRoute.ROUTE_ID_ASYNC_IN) .adviceWith(getCamelContext(), new AdviceWithRouteBuilder() { @Override public void configure() throws Exception { TestUtils.replaceToAsynch(this); weaveAddLast().to("mock:test"); } }); mock.expectedMessageCount(1); // action String output = producer.requestBody((Object) REQ_XML, String.class); // verify mock.assertIsSatisfied(); // verify OK response AsyncHelloResponse res = Tools.unmarshalFromXml(output, AsyncHelloResponse.class); assertThat(res.getConfirmAsyncHello().getStatus(), is(ConfirmationTypes.OK)); // check message header Message inMsg = mock.getExchanges().get(0).getIn(); assertThat((String) inMsg.getHeader(AsynchConstants.OBJECT_ID_HEADER), is("Mr. Parker")); } @Test public void testRouteOut() throws Exception { getCamelContext().getRouteDefinition(AsyncHelloRoute.ROUTE_ID_ASYNC_OUT) .adviceWith(getCamelContext(), new AdviceWithRouteBuilder() { @Override public void configure() throws Exception { weaveAddLast().to("mock:test"); } }); mock.expectedMessageCount(1); // action org.openhubframework.openhub.api.entity.Message msg = createAndSaveMessage(ExternalSystemTestEnum.CRM, ServiceTestEnum.ACCOUNT, "testOp", "payload"); producer.sendBodyAndHeader(AsyncHelloRoute.URI_ASYNC_HELLO_OUT, REQ_XML, AsynchConstants.MSG_HEADER, msg); // verify mock.assertIsSatisfied(); // nothing to verify } }
We should test input and output processing at least.
Webservices testing / mocking
TestWsUriBuilder
- implementation of interface org.openhubframework.openhub.api.route.WebServiceUriBuilder
- does support redirecting webservices inbound and outbound calls to defined "direct" component route
- To enable this, annotation @EnableTestWsUriBuilder is provided, meant to be used in scope of testing class
See javadoc of TestWsUriBuilder for futher reference, and following short snippet of replacing inbound call:
@EnableTestWsUriBuilder @ActiveRoutes(classes = AsyncHelloRoute.class) public class AsyncHelloRouteTest extends AbstractDbTest { private static final String REQ_XML = "<asyncHelloRequest xmlns=\"http://openhubframework.org/ws/HelloService-v1\">" + " <name>Mr. Parker</name>" + "</asyncHelloRequest>"; @Produce(uri = TestWsUriBuilder.URI_WS_IN + "asyncHelloRequest") private ProducerTemplate producer; ... // inbound call final String response = producer.requestBody((Object) REQ_XML, String.class);
Related content
How to write routes?
How to write routes?
More like this
Development tips
Development tips
More like this
Best practices
Best practices
More like this
Best practices
Best practices
More like this
Development tips
Development tips
More like this
External configuration model
External configuration model
More like this