Hamcrest is a framework for writing matcher objects. It allows you to define match rules declaratively. Use Hamcrest’s assertThat construct and the standard set of matchers, both of which you can statically import:
In order to invoke a component service, you must inject an invoker for certain ServiceOperation. When injecting a service operation, specify it in [service_name].[operation_name] notation.
import org.switchyard.test.Invoker;
...
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(mixins = CDIMixIn.class)
public class ExampleServiceTest {
@ServiceOperation("ExampleService.submitOperation")
private Invoker submitOperation;
@Test
public void testOK() throws Exception {
ParamIn testParam = new ParamIn()
.set...(...);
ParamOut result = submitOperation
.sendInOut(testParam)
.getContent(ParamOut.class);
Assert....
}
@Test
public void testForFault() throws Exception {
ParamIn testParam = new ParamIn()
.set...(...);
try{
// This method invocation should throw a fault
ParamOut result = submitOperation
.sendInOut(testParam)
.getContent(ParamOut.class);
Assert.fail
} catch (InvocationFaultException ifex){
Assert.... // Assert for correct type of exception
}
}
import org.switchyard.test.Invoker;
...
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(mixins = CDIMixIn.class)
public class ExampleServiceTest {
@ServiceOperation("ExampleService.submitOperation")
private Invoker submitOperation;
@Test
public void testOK() throws Exception {
ParamIn testParam = new ParamIn()
.set...(...);
ParamOut result = submitOperation
.sendInOut(testParam)
.getContent(ParamOut.class);
Assert....
}
@Test
public void testForFault() throws Exception {
ParamIn testParam = new ParamIn()
.set...(...);
try{
// This method invocation should throw a fault
ParamOut result = submitOperation
.sendInOut(testParam)
.getContent(ParamOut.class);
Assert.fail
} catch (InvocationFaultException ifex){
Assert.... // Assert for correct type of exception
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
An invocation to a service operation can throw a InvocationFaultException whenever the method throws a fault. So catching this exception is similar to validating for the fault being thrown.
You can:
Check against original exception by checking the type of the InvocationFaultException:
ifex.isType(MyOriginalException.class)
ifex.isType(MyOriginalException.class)
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Use the JUnit functionality of setting the expected exception in the test:
While testing a component invocation, you can test for the appropriate transformation with additional methods on the invocation. You can do this for the input transformation, as well as for the output transformation as shown below:
...
@ServiceOperation("ExampleService.submitOperation")
private Invoker serviceOperationInvocation;
@Test
public void testForInputTransformation() throws Exception {
ParamOut result = serviceOperationInvocation
.inputType(QName.valueOf("{urn:com.examaple:service:1.0"}submitOperation))
.sendInOut(....)
.getContent(ParamOut.class);
Assert.... // Assert that result is OK, so transformation was OK
}
@Test
public void testForOutputXMLTransformation() throws Exception {
ParamIn testParam = new ParamIn()
.set...(...);
ParamOut result = serviceOperationInvocation
.expectedOutputType(QName.valueOf("{urn:com.examaple:service:1.0"}submitOperationResponse))
.sendInOut(testParam)
.getContent(Element.class); // Expect Element as transformation is for XML
XMLAssert.... // Assert that result is what is expected
}
...
@ServiceOperation("ExampleService.submitOperation")
private Invoker serviceOperationInvocation;
@Test
public void testForInputTransformation() throws Exception {
ParamOut result = serviceOperationInvocation
.inputType(QName.valueOf("{urn:com.examaple:service:1.0"}submitOperation))
.sendInOut(....)
.getContent(ParamOut.class);
Assert.... // Assert that result is OK, so transformation was OK
}
@Test
public void testForOutputXMLTransformation() throws Exception {
ParamIn testParam = new ParamIn()
.set...(...);
ParamOut result = serviceOperationInvocation
.expectedOutputType(QName.valueOf("{urn:com.examaple:service:1.0"}submitOperationResponse))
.sendInOut(testParam)
.getContent(Element.class); // Expect Element as transformation is for XML
XMLAssert.... // Assert that result is what is expected
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
You can use XMLUnit and XMLAssert from org.custommonkey.xmlunit to ease validations.
Mocking a component may be useful, so it is never invoked for the sake of a test. For this, SwitchYardTestKit provides with the ability of adding, replacing, or removing services.
// replace existing implementation for testing purposes
testKit.removeService("MyService");s
final MockHandler myService = testKit.registerInOnlyService("MyService");
.... // Invoke the service under test
// Assert what has arrived ath the mocked service
final LinkedBlockingQueue<Exchange> recievedMessages = myService.getMessages();
assertThat(recievedMessages, is(notNullValue()));
final Exchange recievedExchange = recievedMessages.iterator().next();
assertThat(recievedExchange.getMessage().getContent(String.class), is(equalTo(...)));
// replace existing implementation for testing purposes
testKit.removeService("MyService");s
final MockHandler myService = testKit.registerInOnlyService("MyService");
.... // Invoke the service under test
// Assert what has arrived ath the mocked service
final LinkedBlockingQueue<Exchange> recievedMessages = myService.getMessages();
assertThat(recievedMessages, is(notNullValue()));
final Exchange recievedExchange = recievedMessages.iterator().next();
assertThat(recievedExchange.getMessage().getContent(String.class), is(equalTo(...)));
Copy to ClipboardCopied!Toggle word wrapToggle overflow
If you want to assert what has arrived or produced in the MockHandler, you can use the following options:
getMessages(): This provides with the list of received messages.
getFaults(): This provides with the list of prodced faults.
If the service is InOut, you may need to mock a response. You can use the following options:
forwardInToOut()
forwardInToFault()
replyWithOut(Object)
replyWithFault(Object)
For example:
final MockHandler mockHandler = testKit.registerInOutService("MyService");
mockHandler.forwardInToOut();
final MockHandler mockHandler = testKit.registerInOutService("MyService");
mockHandler.forwardInToOut();
Copy to ClipboardCopied!Toggle word wrapToggle overflow
If you want to instruct the MockHandler to wait for certain message, you can use the following options:
waitForOkMessage()
waitForFaultMessage()
The MockHandler waits for 5 seconds by default, unless instructed to wait for a different period with setWaitTimeout(milis).
In some cases, the service you are mocking may be called
Twice in the context of a single unit test, or
Multiple times for the same method, or
Multiple times for different methods
In this case, you can register an ExchangeHandler with the mock, while registering and replacing the original service. The ExchangeHandler gets the message, and contains the logic that you need to put to deal with this scenario, as shown below:
testKit.replaceService(qname, new ExchangeHandler() {
@Override
public void handleMessage(Exchange arg0) throws HandlerException {
// Here logic to handle with messages
}
@Override
public void handleFault(Exchange arg0) throws HandlerException {
// Here logic to handle with faults
}
});
testKit.replaceService(qname, new ExchangeHandler() {
@Override
public void handleMessage(Exchange arg0) throws HandlerException {
// Here logic to handle with messages
}
@Override
public void handleFault(Exchange arg0) throws HandlerException {
// Here logic to handle with faults
}
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
You can reuse this ExchangeHandler by making it a named class (not anonymous).
In the case of multiple invocation of the same method, the ExchangeHandler keeps track of the invocation number, in case it has to answer with different messages:
testKit.replaceService(qname, new ExchangeHandler() {
int call=1;
@Override
public void handleMessage(Exchange exchange) throws HandlerException {
if (call++ == 1){ // First call
// Do whatever wants to be done as result of this operation call, and return the expected output
Result result = ...; / Result is return type for operation store
exchange.send(exchange.createMessage().setContent(result));
}else if (call++ == 2){ // Second call
// Do whatever wants to be done as result of this operation call, and return the expected output
Result result = ...; / Result is return type for operation store
exchange.send(exchange.createMessage().setContent(result));
}else{
throw new HandlerException("This mock should not be called more than 2 times");
}
}
@Override
public void handleFault(Exchange exchange) throws HandlerException {
// Here logic to handle with faults
}
});
testKit.replaceService(qname, new ExchangeHandler() {
int call=1;
@Override
public void handleMessage(Exchange exchange) throws HandlerException {
if (call++ == 1){ // First call
// Do whatever wants to be done as result of this operation call, and return the expected output
Result result = ...; / Result is return type for operation store
exchange.send(exchange.createMessage().setContent(result));
}else if (call++ == 2){ // Second call
// Do whatever wants to be done as result of this operation call, and return the expected output
Result result = ...; / Result is return type for operation store
exchange.send(exchange.createMessage().setContent(result));
}else{
throw new HandlerException("This mock should not be called more than 2 times");
}
}
@Override
public void handleFault(Exchange exchange) throws HandlerException {
// Here logic to handle with faults
}
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
In the case of multiple invocation of different methods, the ExchangeHandler checks for operation name, to know which method is being invoked:
testKit.replaceService(qname, new ExchangeHandler() {
@Override
public void handleMessage(Exchange exchange) throws HandlerException {
if (exchange.getContract().getProviderOperation().getName().equals("store")){
// Do whatever wants to be done as result of this operation call, and return the expected output
Result result = ...; / Result is return type for operation store
exchange.send(exchange.createMessage().setContent(result));
}else if (exchange.getContract().getProviderOperation().getName().equals("getId")){
// Do whatever wants to be done as result of this operation call, and return the expected output
exchange.send(exchange.createMessage().setContent(1)); // This operation returns a Int
}else{
throw new HandlerException("No operation with that name should be executed");
}
}
@Override
public void handleFault(Exchange exchange) throws HandlerException {
// Here logic to handle with faults
}
});
testKit.replaceService(qname, new ExchangeHandler() {
@Override
public void handleMessage(Exchange exchange) throws HandlerException {
if (exchange.getContract().getProviderOperation().getName().equals("store")){
// Do whatever wants to be done as result of this operation call, and return the expected output
Result result = ...; / Result is return type for operation store
exchange.send(exchange.createMessage().setContent(result));
}else if (exchange.getContract().getProviderOperation().getName().equals("getId")){
// Do whatever wants to be done as result of this operation call, and return the expected output
exchange.send(exchange.createMessage().setContent(1)); // This operation returns a Int
}else{
throw new HandlerException("No operation with that name should be executed");
}
}
@Override
public void handleFault(Exchange exchange) throws HandlerException {
// Here logic to handle with faults
}
});
Copy to ClipboardCopied!Toggle word wrapToggle overflow
Use HTTPMixin to test a deployed service, as shown below:
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
scanners = TransformSwitchYardScanner.class,
mixins = {CDIMixIn.class, HTTPMixIn.class})
public class WebServiceTest {
private HTTPMixIn httpMixIn;
@Test
public void invokeWebService() throws Exception {
// Use the HttpMixIn to invoke the SOAP binding endpoint with a SOAP input (from the test classpath)
// and compare the SOAP response to a SOAP response resource (from the test classpath)...
httpMixIn.setContentType("application/soap+xml");
httpMixIn.postResourceAndTestXML("http://localhost:18001/service-context/ServiceName", "/xml/soap-request.xml", "/xml/soap-response.xml");
}
}
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(
scanners = TransformSwitchYardScanner.class,
mixins = {CDIMixIn.class, HTTPMixIn.class})
public class WebServiceTest {
private HTTPMixIn httpMixIn;
@Test
public void invokeWebService() throws Exception {
// Use the HttpMixIn to invoke the SOAP binding endpoint with a SOAP input (from the test classpath)
// and compare the SOAP response to a SOAP response resource (from the test classpath)...
httpMixIn.setContentType("application/soap+xml");
httpMixIn.postResourceAndTestXML("http://localhost:18001/service-context/ServiceName", "/xml/soap-request.xml", "/xml/soap-response.xml");
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
You can also use HTTPMixin from a main class, as shown below:
/**
* Only execution point for this application.
* @param ignored not used.
* @throws Exception if something goes wrong.
*/
public static void main(final String[] ignored) throws Exception {
HTTPMixIn soapMixIn = new HTTPMixIn();
soapMixIn.initialize();
try {
String result = soapMixIn.postFile(URL, XML);
System.out.println("SOAP Reply:\n" + result);
} finally {
soapMixIn.uninitialize();
}
}
/**
* Only execution point for this application.
* @param ignored not used.
* @throws Exception if something goes wrong.
*/
public static void main(final String[] ignored) throws Exception {
HTTPMixIn soapMixIn = new HTTPMixIn();
soapMixIn.initialize();
try {
String result = soapMixIn.postFile(URL, XML);
System.out.println("SOAP Reply:\n" + result);
} finally {
soapMixIn.uninitialize();
}
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
When you need to test an application that has a JMS binding, you may want to test with the binding itself. In such cases, you can use HornetQMixIn. HornetQMixIn gets its configuration from the following two files, which must be present on the classpath for the test:
hornetq-configuration.xml: This file contains the configuration for the HornetQ server.
You can use TransactionMixIn to test your required services with a transaction. TransactionMixIn with combination of CDIMixIn injects a UserTransaction object when required. If you need explicit access, you can use @Inject in the UserTransaction object. otherwise, it is injected in SwitchYard’s functionalities. This MixIn introduces NamingMixIn, as it is a required dependency.
You can use the following annotation on the test class and create your reduced <switchyard-XXXX.xml> within the test/resources folder at the same package level as your test class:
The test framework defaults to a mode where the entire application descriptor is processed during a test run. This means all gateway bindings and service implementations are activated during each test. There are times when this may not be appropriate. So you must allow activators to be selectively enabled or disabled based on your test configuration. In the example below, SOAP bindings are excluded from all tests. This means that SOAP gateway bindings are not activated when the test framework loads the application.
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(config = "testconfigs/switchyard-01.xml" exclude="soap")
public class NoSOAPTest {
...
}
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(config = "testconfigs/switchyard-01.xml" exclude="soap")
public class NoSOAPTest {
...
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
The example below includes only CDI bean services as defined in the application descriptor:
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(config = "testconfigs/switchyard-02.xml" include="bean")
public class BeanServicesOnlyTest {
...
}
@RunWith(SwitchYardRunner.class)
@SwitchYardTestCaseConfig(config = "testconfigs/switchyard-02.xml" include="bean")
public class BeanServicesOnlyTest {
...
}
Copy to ClipboardCopied!Toggle word wrapToggle overflow
You may need to add some procedures before you perform the test. The JUnit @Before operation is invoked immediately after the application is deployed. However, you can not use it if you expect something to happen before deployment.
JUnit @Before operation is invoked right after the application is deployed. So, you can not use @Before operation if you expect something before deployment. Use @BeforeDeploy annotation when you need to add some procedures before a test is performed.
We help Red Hat users innovate and achieve their goals with our products and services with content they can trust. Explore our recent updates.
Making open source more inclusive
Red Hat is committed to replacing problematic language in our code, documentation, and web properties. For more details, see the Red Hat Blog.
About Red Hat
We deliver hardened solutions that make it easier for enterprises to work across platforms and environments, from the core datacenter to the network edge.