Giter Site home page Giter Site logo

mockito-soap-cxf's Introduction

Build Status Maven Central

mockito-soap-cxf

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.

License

Apache 2.0

Obtain

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).

Usage

Junit 5

If you prefer skipping to a full example, see this unit test.

Basics

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.

JUnit 4

If you prefer skipping to a full example, see this unit test.

Basics

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.

Mocking

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));

SOAP Faults

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.

MTOM (binary attachments)

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.

Running in parallel (Junit 4 only)

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.

Troubleshooting

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.

CXF version 2.x

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.

History

  • 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

mockito-soap-cxf's People

Contributors

amichair avatar aukevanleeuwen avatar belano avatar dependabot[bot] avatar skjolber avatar snyk-bot avatar ttmaza avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

mockito-soap-cxf's Issues

Fix support for wsdl/schema validation

It would be nice to have schema validation with wsdl work. It currently throws exception because the proxy gets a default invalid name:
javax.xml.ws.WebServiceException: org.apache.cxf.service.factory.ServiceConstructionException: Could not find definition for service {http://proxy.sun.com/}$Proxy112Service at org.apache.cxf.jaxws.EndpointImpl.doPublish(EndpointImpl.java:375) at org.apache.cxf.jaxws.EndpointImpl.publish(EndpointImpl.java:255) at com.skjolberg.mockito.soap.SoapEndpointRule.proxy(SoapEndpointRule.java:282)

Is there a workaround for fixing this, or is it on the roadmap to make it work out of the box?

Thanks

Ability to mock out an invalid (non-xml) return from endpoint?

Hi, I'm really glad I found this utility as it helps simplify my testing. I have a use case that is probably very much an edge case and I wish I didn't even have to deal with it, but occasionally I have to deal with the fact that the endpoint I'm using is returning a text/html response instead of xml. (This is a known bug on my provider, but since I don't control it I have to handle it). The result ends up in an UnsupportedMediaException instead of a SOAP fault. I was really just wondering if this is possible with this library or not.

Thank you

Support to mock soap faults for different HTTP Status Code

Hi Thomas, This really helped me a lot to mock the services for unit testing in spring boot/camel, I'm trying to throw a soap fault response with different HTTP status codes and it only works for HTTP 500. When i tired with 401 or 402, I got the following error "org.apache.cxf.interceptor.Fault: Could not send Message" instead of getting the soap fault response. see if you can help here ?

Release amichair PR

@amichair I've merged your pull-requests, very good work! If you're happy / finished, I'll release it later today. ๐Ÿ‘ ๐Ÿ‘

RuntimeException: Already a destination

Got this exception only once, in a Travis build. The same code on local build or after re-teriggering the Travis build with no code changes did not reproduce the error. Seems unrelated to the PR it happened on, and more like something to do with the random selection of ports by CXF or something wrong with how we create and use the address in Destination/Endpoint/Server. Perhaps someone who really knows CXF in depth should have a look...

java.lang.RuntimeException: Already a destination on http://localhost:36013
at org.apache.cxf.transport.http.DestinationRegistryImpl.addDestination(DestinationRegistryImpl.java:54)
at org.apache.cxf.transport.http.HTTPTransportFactory.getDestination(HTTPTransportFactory.java:286)
at org.apache.cxf.binding.soap.SoapTransportFactory.getDestination(SoapTransportFactory.java:135)
at org.apache.cxf.endpoint.ServerImpl.initDestination(ServerImpl.java:85)
at org.apache.cxf.endpoint.ServerImpl.(ServerImpl.java:64)
at org.apache.cxf.frontend.ServerFactoryBean.create(ServerFactoryBean.java:182)
at org.apache.cxf.jaxws.JaxWsServerFactoryBean.create(JaxWsServerFactoryBean.java:211)
at org.apache.cxf.jaxws.EndpointImpl.getServer(EndpointImpl.java:460)
at org.apache.cxf.jaxws.EndpointImpl.getServer(EndpointImpl.java:384)
at com.skjolberg.mockito.soap.SoapEndpointRule.proxy(SoapEndpointRule.java:151)
at com.skjolberg.mockito.soap.SoapServiceRule.mock(SoapServiceRule.java:143)
at com.skjolberg.mockito.soap.SoapServiceRule.mock(SoapServiceRule.java:64)
at com.skjolberg.mockito.soap.BankCustomerSoapEndpointClassRuleTest.setup(BankCustomerSoapEndpointClassRuleTest.java:87)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:75)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:86)
at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:239)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:84)
at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:251)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:97)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.rules.ExternalResource$1.evaluate(ExternalResource.java:48)
at org.junit.rules.RunRules.evaluate(RunRules.java:20)
at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:190)
at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:252)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:141)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165)
at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85)
at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75)

Improvement: would like to be able to use local:// transport

Hey! Thanks for your library, something I had in mind to create but a quick google search returned me this :-)

Anyway, I'd like to use this library in combination with using the local:// transport, but there is some code which validates the URL in the SoapServerRule which prevents that from working.

		try {
			new URL(address);
		} catch (MalformedURLException e) {
			throw new IllegalArgumentException("Expected valid address: " + address, e);
		}

I'd thought it would be easy enough to fix, (and it is), but I had some problems with the test suite because apparently deep down in CXF there is still some shared state in a ThreadLocal that was causing some issues when switching between transports in the tests.

I have a PR upcoming, so you can have a look. This issue is more or less if people are searching for similar issues.

Multiple registered services in the same endpoint result to error 'Message part ... was not recognized'

I'm using @ClassRule and multiple services reusing the same http port.
If multiple services are mocked using Class definitions, some of wsdl definitions get lost.

Attached modified unit test from project codebase that reproduces the issue
(https://github.com/skjolber/mockito-soap-cxf/files/2922348/BankCustomerSoapEndpointClassRuleTest.zip)

Exception is:
20:00:41.664 [qtp1725008249-16] WARN o.a.cxf.phase.PhaseInterceptorChain - Interceptor for {http://proxy.sun.com/}$Proxy81Service has thrown exception, unwinding now org.apache.cxf.interceptor.Fault: Message part {http://example.shop.skjolber.github.com/v1}getItemsRequest was not recognized. (Does it exist in service WSDL?) at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.validatePart(DocLiteralInInterceptor.java:252) at org.apache.cxf.wsdl.interceptors.DocLiteralInInterceptor.handleMessage(DocLiteralInInterceptor.java:191) at org.apache.cxf.phase.PhaseInterceptorChain.doIntercept(PhaseInterceptorChain.java:308) at org.apache.cxf.transport.MultipleEndpointObserver.onMessage(MultipleEndpointObserver.java:98) at org.apache.cxf.transport.http.AbstractHTTPDestination.invoke(AbstractHTTPDestination.java:267) at org.apache.cxf.transport.http_jetty.JettyHTTPDestination.doService(JettyHTTPDestination.java:247) at org.apache.cxf.transport.http_jetty.JettyHTTPHandler.handle(JettyHTTPHandler.java:79) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) at org.eclipse.jetty.server.handler.ScopedHandler.nextHandle(ScopedHandler.java:257) at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1317) at org.eclipse.jetty.server.handler.ScopedHandler.nextScope(ScopedHandler.java:205) at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1219) at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:144) at org.eclipse.jetty.server.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:219) at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:132) at org.eclipse.jetty.server.Server.handle(Server.java:531) at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:352) at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:260) at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:281) at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:102) at org.eclipse.jetty.io.ChannelEndPoint$2.run(ChannelEndPoint.java:118) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.runTask(EatWhatYouKill.java:333) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.doProduce(EatWhatYouKill.java:310) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.tryProduce(EatWhatYouKill.java:168) at org.eclipse.jetty.util.thread.strategy.EatWhatYouKill.produce(EatWhatYouKill.java:132) at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:762) at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:680) at java.lang.Thread.run(Thread.java:745)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.