SOAP web-service mocking utility which creates real service endpoints on local ports using webserver instances. These endpoints delegate requests directly to mocks.
Users will benefit from
- full stack client testing
- interceptors
- handlers
- simple JUnit Rule setup
- SOAP-Fault helper
all with the regular advantages of Mockito.
Bugs, feature suggestions and help requests can be filed with the issue-tracker.
The project is based on Maven and is available form central Maven repository.
Example dependency config:
<dependency>
<groupId>com.github.skjolber</groupId>
<artifactId>mockito-soap-cxf</artifactId>
<version>1.2.0</version>
<scope>test</scope>
</dependency>
For JDK9+, add module com.github.skjolber.mockito.soap
.
Add an exclusion for the cxf-core
artifact
<exclusions>
<exclusion>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-core</artifactId>
</exclusion>
</exclusions>
If you prefer skipping to a full example, see this unit test.
Add a SoapServiceExtension
@ExtendWith(SoapServiceExtension.class)
and mock service endpoints by using
private MyServicePortType serviceMock;
@BeforeEach
public void setup(SoapServiceExtension soap) {
serviceMock = soap.mock(MyServicePortType.class, "http://localhost:12345");
}
or, preferably
private MyServicePortType serviceMock;
@BeforeEach
public void setup(SoapServiceExtension soap) {
soap.mock(MyServicePortType.class, "http://localhost:12345", Arrays.asList("classpath:wsdl/MyService.xsd"));
}
for schema validation. The returned serviceMock
instance is a normal Mockito mock(..) object.
If you prefer skipping to a full example, see this unit test.
Create a SoapServiceRule
@Rule
public SoapServiceRule soap = SoapServiceRule.newInstance();
add a field
private MyServicePortType serviceMock;
and mock service endpoints by using
@Before
public void mockService() {
serviceMock = serviceMock = soap.mock(MyServicePortType.class, "http://localhost:12345");
}
or, preferably
serviceMock = soap.mock(MyServicePortType.class, "http://localhost:12345", Arrays.asList("classpath:wsdl/MyService.xsd"));
for schema validation. The returned serviceMock
instance is a normal Mockito mock(..) object.
Create mock response via code
// init response
GetAccountsResponse mockResponse = new GetAccountsResponse();
List<String> accountList = mockResponse.getAccount();
accountList.add("1234");
accountList.add("5678");
or from XML
GetAccountsResponse response = jaxbUtil.readResource("/my/test/GetAccountsResponse1.xml", GetAccountsResponse.class);
using your favorite JAXB utility. Then mock
when(serviceMock.getAccounts(any(GetAccountsRequest.class))).thenReturn(mockResponse);
and apply standard Mockito test approach. After triggering calls to the mock service, verify number of method calls
ArgumentCaptor<GetAccountsRequest> argument1 = ArgumentCaptor.forClass(GetAccountsRequest.class);
verify(serviceMock, times(1)).getAccounts(argument1.capture());
and request details
GetAccountsRequest request = argument1.getValue();
assertThat(request.getCustomerNumber(), is(customerNumber));
Mock SOAP faults by adding import
import static com.skjolberg.mockito.soap.SoapServiceFault.*;
then mock doing
when(serviceMock.getAccounts(any(GetAccountsRequest.class))).thenThrow(createFault(exception));
or mock directly using an XML string / w3c DOM node.
CXF SOAP clients support MTOM of out the box, enable MTOM in the service mock using
serviceMock = soap.mock(BankCustomerServicePortType.class, bankCustomerServiceAddress, properties("mtom-enabled", Boolean.TRUE));
and add a DataHandler
to the mock response using
byte[] mockData = new byte[] {0x00, 0x01};
DataSource source = new ByteArrayDataSource(mockData, "application/octet-stream");
mockResponse.setCertificate(new DataHandler(source)); // MTOM-enabled base64binary
See MTOM unit test for an example.
For use-cases which require test-cases to run in parallel, it is possible to mock endpoints on random (free) ports. For the SoapEndpointRule
methods
@ClassRule
public static SoapEndpointRule soap = SoapEndpointRule.newInstance("myPort", "yourPort");
or with port range
@ClassRule
public static SoapEndpointRule soap = SoapEndpointRule.newInstance(10000, 30000, "myPort", "yourPort");
there will be reserved two random free ports. Ports numbers can be retrieved using.
int myPort = soap.getPort("myPort");
and
String myPort = System.getProperty("myPort");
In other words, for property resolvers which include system-properties, the reserved ports are readily available. For example the Spring property expression
http://localhost:${myPort}/selfservice/bank
would effectively point to the mocked webservice at myPort
. For a more complete example, see
this spring unit test.
There seems to be an issue with the use of the -exsh
parameter for passing headers into the mock and schema validation. Rather than supplying the wsdl location, supply the XSD locations to work around the problem until a solution can be found.
If you see exception cause by
No binding factory for namespace http://schemas.xmlsoap.org/soap/ registered.
then you're mixing CXF version 2 and 3 - see above about excluding cxf-core
artifact.
- 1.2.0: JUnit 5 support.
- 1.1.0: Automatic module name; renamed packages accordingly.
- 1.0.5: A lot of refactorings and code cleanups, update dependencies and fix port release - many thanks to amichair!
- 1.0.4: Allow the usage of local:// transport - compliments of aukevanleeuwen
- 1.0.3: MTOM support
- 1.0.2: Support for mocking on (random) free ports (via SoapEndpointRule).
- 1.0.1: Improved JAXB helper methods in SoapServiceFault
- 1.0.0: Initial version