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.
Maven coordinates
Add
<mockito-soap-cxf.version>2.0.0</mockito-soap-cxf.version>
and
<dependency>
<groupId>com.github.skjolber</groupId>
<artifactId>mockito-soap-cxf</artifactId>
<version>${mockito-soap-cxf.version}</version>
</dependency>
or
Gradle coordinates
For
ext {
mockitoSoapCxfVersion = '2.0.0'
}
add
api("com.github.skjolber:mockito-soap-cxf:${mockitoSoapCxfVersion}")
For JDK 9+, add module com.github.skjolber.mockito.soap
.
For JDK 8 or 11 use the 1.2.x
series (override spring and mockito dependency versions).
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 = 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.
- 2.0.0: Move to JDK 17 and Spring 6.x and Mockito 5.x.
- 1.2.1: Maintainence release. JDK 8 (with CXF 3.x and Spring 5.3.x now live at jdk8 branch, on version 1.2.x).
- 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