Unit Test CXF JAX-RS implementation without deploying to server - java

Working on a JAX-RS client using CXF.
Requirement is to test the service side code from unit test case with the help of a test client without deploying the rest service to a server
REST Service we implemented use HTTP headers to pass some information to the WS methods.
All the implementations I came across, so far, have services deployed to a server.
Examples I tried to create a JAX-RS client
WebClient client = WebClient.create(ENDPOINT_ADDRESS);
and
RestWSInterafce proxy = JAXRSClientFactory.create(ENDPOINT_ADDRESS, RestWSInterafce.class);
Client client = WebClient.client(proxy);
WebClient httpClient = WebClient.fromClient(client);
I tried configuring a CXF-Jetty implementation but didn't had any luck. Below is a snapshot from the Spring application context file
<import resource="classpath:META-INF/cxf/cxf.xml"/>
<import resource="classpath:META-INF/cxf/cxf-extension-http-jetty.xml" />
<jaxrs:client id="restWSClient" address="${server.address}" serviceClass="com.xyz.rs.RestWSInterface">
</jaxrs:client>
Is it possible to test without having the rest services deployed to a server?
Edit
My main concern while posting this question is to test the method which expects HttpHeaders elements to be passed in the context. Consider the below GET method from my interface.
#GET
#Produces(MediaType.APPLICATION_JSON + ";charset=UTF-8")
#Path("/getMessage")
public Response getMessage(#Context HttpHeaders headers);
To Unit test this method, instead of calling the interface by deploying the application to the server, I wrote test case to call the implementation class directly and pass an implementor to HttpHeader as input. This solved my issue of unit testing the ws methods without deploying to the server.
public class HttpHeadersImpl implements HttpHeaders {
private MultivaluedMap<String, String> multivaluedMap;
public void setRequestHeaders(MultivaluedMap<String, String> multivaluedMap) {
this.multivaluedMap = multivaluedMap;
}
#Override
public MultivaluedMap<String, String> getRequestHeaders() {
return multivaluedMap;
}
}

You can launch programmaticaly a CXF server from your unit tests without deploying into a server
JAXRSServerFactoryBean sf = new JAXRSServerFactoryBean();
sf.setResourceClasses(TestServiceImpl.class);
sf.setAddress("http://localhost:8080/testrs");
sf.create();
To start the endpoint you will need the cxf-rt-transports-http-jetty dependency
<dependency>
<groupId>org.apache.cxf</groupId>
<artifactId>cxf-rt-transports-http-jetty</artifactId>
<version>3.1.6</version>
</dependency>
The server could be the real or simulated only for testing. With the WebClient you can test the http transport.
If you work with CXF and Spring, you also can initialize the full context using ClassPathXmlApplicationContext and inject the rest server to the unit test client. In this case you can test the services without http transport

Related

Define client target URL at runtime using Quarkus & Resteasy

I need to send HTTP requests from my Quarkus application. Following this guide, I have this RestClient:
#Path("/v1")
#RegisterRestClient
public interface CountriesService {
#GET
#Path("/name/{name}")
Set<Country> getByName(#PathParam String name);
}
In the Path annotation, I can configure the path. But the domain/url to call is defined in a configuration file, according to this paragraph.
# Your configuration properties
org.acme.rest.client.CountriesService/mp-rest/url=https://restcountries.eu/rest #
org.acme.rest.client.CountriesService/mp-rest/scope=javax.inject.Singleton #
In my case, I need this URL to be defined programmatically at runtime, as I receive it as a callback URL.
Is there a way to do that?
Quarkus Rest Client, and Quarkus Rest Client Reactive, implement the MicroProfile Rest specification and as such allow creating client stubs with RestClientBuilder programmatically, e.g.:
public class SomeService {
public Response doWorkAgainstApi(URI apiUri, ApiModel apiModel) {
RemoteApi remoteApi = RestClientBuilder.newBuilder()
.baseUri(apiUri)
.build(RemoteApi.class);
return remoteApi.execute(apiModel);
}
}
See https://download.eclipse.org/microprofile/microprofile-rest-client-2.0/microprofile-rest-client-spec-2.0.html#_sample_builder_usage
You cannot achieve this with client created with the #RegisterRestClient annotation

Set up proxy data to Spring SOAP web service template

I'm working on an application where I have to consume a SOAP webservice and convert it to Rest based webservices. I followed the tutorial from Spring team and was capable to generate pojos, but when I try to make the call using the webServiceTemplate I have an error that the host is not recognized which is basically because I'm behind a proxy in our company.
The technology stack I'm using is Spring boot with web module and spring-ws-core, and I would like to know how to set up my proxy data in the webServiceTemplate.
Thanks
Try to setup the template according this answer.
Afterwards you should be able to set it within your class extending WebServiceGatewaySupport using
setWebServiceTemplate(WebServiceTemplate webServiceTemplate)
After a lot of research, I came up with a programmatic solution. Once you defined your SOAP client that will extend WebServiceGatewaySupport class, I created a configuration class (annotated with #configuration that will declare a bean of my SOAP client. In this method, I used the following code to setup my proxy information and thus I was able to consume my web service:
#Bean
public CommerceSoapClient commerceSoapClient(Jaxb2Marshaller marshaller) {
CommerceSoapClient commerceService = new CommerceSoapClient();
//Setup proxy
HttpClientBuilder builder = HttpClientBuilder.create();
builder.addInterceptorFirst(new HttpComponentsMessageSender.RemoveSoapHeadersInterceptor());
HttpHost proxy = new HttpHost("127.0.0.1", 8080);
builder.setProxy(proxy);
CloseableHttpClient httpClient = builder.build();
HttpComponentsMessageSender messageSender = new HttpComponentsMessageSender(httpClient);
WebServiceTemplate webServiceTemplate = new WebServiceTemplate();
webServiceTemplate.setMessageSender(messageSender);
webServiceTemplate.setDefaultUri("http://your webservice address path");
webServiceTemplate.setUnmarshaller(marshaller);
webServiceTemplate.setMarshaller(marshaller);
commerceService.setDefaultUri("https://your webservice address path");
commerceService.setWebServiceTemplate(webServiceTemplate);
return commerceService;
}

How to use WireMock on a Feign client in a Spring Boot application?

I have a class that makes use of a Feign client. Previously I used Mockito and gave a stored response for each of the method calls in the Feign client. Now I want to use WireMock, so that I can see that my code handles different kinds of response codes correctly. How do I go about doing this? I can't figure out how to wire up my Feign client in the test, and wire it up so that it uses Wiremock instead of the URL I've setup in my application.yml file. Any pointers would be greatly appreciated.
Maybe you want to look at this project https://github.com/ePages-de/restdocs-wiremock
This helps you generate and publish wiremock snippets in your spring mvc tests (using spring-rest-docs).
Finally you can use these snippets to start a wiremock server to serve these recorded requests in your test.
If you shy away from this integrated solution you could just use the wiremock JUnit rule to fire up your wiremock server during your test.
http://wiremock.org/docs/junit-rule/
Here is a sample test that uses a dynamic wiremock port and configures ribbon to use this port: (are you using feign and ribbon?)
#WebAppConfiguration
#RunWith(SpringRunner.class)
#SpringBootTest()
#ActiveProfiles({"test","wiremock"})
public class ServiceClientIntegrationTest {
#Autowired //this is the FeignClient service interface
public ServiceClient serviceClient;
#ClassRule
public static WireMockRule WIREMOCK = new WireMockRule(
wireMockConfig().fileSource(new ClasspathFileSource("path/to/wiremock/snipptes")).dynamicPort());
#Test
public void createSome() {
ServiceClient.Some t = serviceClient.someOperation(new Some("some"));
assertTrue(t.getId() > 0);
}
//using dynamic ports requires to configure the ribbon server list accordingly
#Profile("wiremock")
#Configuration
public static class TestConfiguration {
#Bean
public ServerList<Server> ribbonServerList() {
return new StaticServerList<>(new Server("localhost", WIREMOCK.port()));
}
}
}

Consuming a RESTful WebService passing a JSON object as request body

I've defined a RESTful WebService (by using RESTEasy on JBoss AS 7) that consumes a JSON data stream.
#PUT
#Path("/send")
#Consumes(MediaType.APPLICATION_JSON)
public Response consumeJSON(Student student) {
String output = student.toString();
// Do something...
return Response.status(200).entity(output).build();
}
How can I call my WS from another Spring-based webapp, by properly using the RestTemplate, mapping a Java Object to JSON and passing it as request body?
Note: I'm asking about Spring with the aim to investigate the facilities provided by the framework. I well know that it is possible to do that by defining manually the request body.
Cheers, V.
In the client application, you can create an interface with the same signature as the one you expose on the server side, and the same path.
Then, in the spring configuration file, you can use the RESTeasy client API to generate a proxy connecting to the exposed webservice.
In the client application, it would look like this :
SimpleClient.java
#PUT
#Path("/send")
#Consumes(MediaType.APPLICATION_JSON)
public Response consumeJSON(Student student);
Config.java
#Bean
public SimpleClient getSimpleClient(){
Client client = ClientFactory.newClient();
WebTarget target = client.target("http://example.com/base/uri");
ResteasyWebTarget rtarget = (ResteasyWebTarget)target;
SimpleClient simple = rtarget.proxy(SimpleClient.class);
return simple;
}
Then, in the place where you want to invoke this web service, you inject it with Spring and you can call the method. RESTeasy will search for the webservice matching with with your client (according to the path and the request type) and will create a connection.
Launcher.java
#Resource
private SimpleClient simpleClient;
public void sendMessage(Student student) {
simpleClient.consumeJSON(student);
}
Docs on the RESTesay client API : http://docs.jboss.org/resteasy/docs/3.0.7.Final/userguide/html/RESTEasy_Client_Framework.html
Hope this was helpfull.

What is the best way to unit test REST Endpoints (Jersey)

I have a REST controller that has multiple GET/POST/PUT methods that all respond/request JSON.
I am not using Spring in this application (yet).
I was looking into the REST-assured framework and I like how that looks but I can only use it when my web server is up and running.
Is there a way for me to run a in-memory web server, or something like that?
Are there any examples of REST endpoint testing that someone can provide?
If you are using JAX-RS 2.0 you should find your answer here
You can take a look at the example also
An integration test example, could be:
public class CustomerRestServiceIT {
#Test
public void shouldCheckURIs() throws IOException {
URI uri = UriBuilder.fromUri("http://localhost/").port(8282).build();
// Create an HTTP server listening at port 8282
HttpServer server = HttpServer.create(new InetSocketAddress(uri.getPort()), 0);
// Create a handler wrapping the JAX-RS application
HttpHandler handler = RuntimeDelegate.getInstance().createEndpoint(new ApplicationConfig(), HttpHandler.class);
// Map JAX-RS handler to the server root
server.createContext(uri.getPath(), handler);
// Start the server
server.start();
Client client = ClientFactory.newClient();
// Valid URIs
assertEquals(200, client.target("http://localhost:8282/customer/agoncal").request().get().getStatus());
assertEquals(200, client.target("http://localhost:8282/customer/1234").request().get().getStatus());
assertEquals(200, client.target("http://localhost:8282/customer?zip=75012").request().get().getStatus());
assertEquals(200, client.target("http://localhost:8282/customer/search;firstname=John;surname=Smith").request().get().getStatus());
// Invalid URIs
assertEquals(404, client.target("http://localhost:8282/customer/AGONCAL").request().get().getStatus());
assertEquals(404, client.target("http://localhost:8282/customer/dummy/1234").request().get().getStatus());
// Stop HTTP server
server.stop(0);
}
}

Categories

Resources