Spring WS + JAXB Testing - junit4

I'm trying to write junit test for simple Enpoint web service:
#Endpoint
public class TestWS {
#PayloadRoot(localPart = "GetAllPlayersRequest", namespace = NAMESPACE_URI)
public #ResponsePayload GetAllPlayersResponse handleGetAllPlayersRequest() {
...
}
}
My test looks like:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:**/tb-ws-servlet.xml" })
public class TeambridgeWSTest extends AbstractWebServiceServerTest {
private MockWebServiceClient client;
#Autowired
public void setApplicationContex(ApplicationContext applicationContext) {
client = createClient(applicationContext);
}
#Test
public void shouldReturnAllPlayers() throws Exception {
ParametrizableRequestCreator message = withMessage("GetAllPlayersRequest.xml");
client.sendRequest(message).andExpect(message("messages="GetAllPlayersResponse.xml"));
}
}
and GetAllPlayersRequest.xml:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sch="http://ws.tb.company.com/schemas">
<soapenv:Header/>
<soapenv:Body>
<sch:GetAllPlayersRequest/>
</soapenv:Body>
</soapenv:Envelope>
I have no idea why I get
No endpoint mapping found for [SaajSoapMessage http://ws.tb.company.com/schemas}GetAllPlayersRequest]
I'm experienced in Spring, but still new in Spring WS. Do you have any suggestions to my problem?

What is the value of NAMESPACE_URI? I suppose it's:
private static final String NAMESPACE_URI = "http://ws.tb.company.com/schemas";
You've also configured your Spring web service XML file using annotation driven, haven't you?
<context:component-scan base-package="your.package.here"/>
<sws:annotation-driven/>

Related

RestEasy Webservice Server Tutorial Baeldung not working Wildfly 20

I am new to rest webservices. I wanted to test the tutorial https://www.baeldung.com/resteasy-tutorial with wildfly 20. I created a maven project with the code I got from github. I built the project and sucessfully deployed it.
But if I try to make rest calls via postman (i.e. http://127.0.0.1:8080/resteasy/movies/listmovies) I get "Error 404 not found" errors.
Here is the web.xml
<?xml version="1.0" encoding="UTF-8"?>
<web-app version="3.0" xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd">
<display-name>resteasy</display-name>
<context-param>
<param-name>resteasy.servlet.mapping.prefix</param-name>
<param-value>/rest</param-value>
</context-param>
Here is the MovieCrudService.java
#Path("/movies")
public class MovieCrudService {
private Map<String, Movie> inventory = new HashMap<String, Movie>();
#GET
#Path("/")
#Produces({ MediaType.TEXT_PLAIN })
public Response index() {
return Response.status(200).header("Access-Control-Allow-Origin", "*")
.header("Access-Control-Allow-Headers", "origin, content-type, accept, authorization")
.header("Access-Control-Allow-Credentials", "true")
.header("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS, HEAD").entity("").build();
}
...
#GET
#Path("/listmovies")
#Produces({ "application/json" })
public List<Movie> listMovies() {
return inventory.values().stream().collect(Collectors.toCollection(ArrayList::new));
}
Here is RestEasyServices.java
#ApplicationPath("/rest")
public class RestEasyServices extends Application {
private Set<Object> singletons = new HashSet<Object>();
public RestEasyServices() {
singletons.add(new MovieCrudService());
}
#Override
public Set<Object> getSingletons() {
return singletons;
}
#Override
public Set<Class<?>> getClasses() {
return super.getClasses();
}
#Override
public Map<String, Object> getProperties() {
return super.getProperties();
}
}
Movie.java
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlType;
#XmlAccessorType(XmlAccessType.FIELD)
#XmlType(name = "movie", propOrder = { "imdbId", "title" })
public class Movie {
protected String imdbId;
protected String title;
public Movie(String imdbId, String title) {
this.imdbId = imdbId;
this.title = title;
}
public Movie() {}
public String getImdbId() {
return imdbId;
}
...
What am I doing wrong?
Thanks a lot, Nicole
Your servlet mapping is:
<param-value>/rest</param-value>
So the url you have to call should include "/rest" between the webapp context-path (/resteasy) and the resource path (/movies/listmovies):
http://127.0.0.1:8080/resteasy/rest/movies/listmovies

Spring Boot o.s.web.servlet.pagenotfound

I am trying to call spring-boot rest controller but it throws o.s.web.servlet.pagenotfound spring boot, I have seen too many answers here but none of these helped me.
controller class is as below
#RestController
#RequestMapping("/users")
public class UsersController {
#Autowired
private UsersRepository usersRepository;
#GetMapping("/users")
public List<Users> getAllUsers() {
return usersRepository.findAll();
}
}
And application.yml is as below
spring.datasource.url = jdbc:mysql://localhost:3306/mydb?useSSL=false
spring.datasource.username=mine
spring.datasource.password=mine
kindly let me know if any further information required
I had the same problem, there should be a problem with your URL. You must be hitting the wrong URL.
I'm assuming you are using Postman for testing the GET Request.
Check if you are hitting through GET Request, and the format is JSON.
And try the below:
#RestController
#RequestMapping(value = "/")
public class UsersController {
#Autowired
private UsersRepository usersRepository;
#GetMapping("/users")
public List<Users> getAllUsers() {
return usersRepository.findAll();
}
}

How to test SOAPAction header with Spring WS Test

My app is calling an external Soap WS using spring-ws's WebServiceTemplate, which I mock in my tests using MockWebServiceServer.
It works fine to simulate the response depending on the request payload.
But now I'd like to test which SOAP action is called. It should be defined in the "SOAPAction" HTTP header of the request.
I'm using Spring-WS 2.1.4.
Does anyone know if it's possible to test that and how?
Here is my test class :
public class MyWebServiceTest {
#Autowired
private WebServiceTemplate webServiceTemplate;
private MockWebServiceServer mockServer;
#Before
public void createServer() throws Exception {
mockServer = MockWebServiceServer.createServer(webServiceTemplate);
}
#Test
public void callStambiaWithExistingFileShouldSuccess() throws IOException {
Resource requestPayload = new ClassPathResource("request-payload.xml");
Resource responseSoapEnvelope = new ClassPathResource("success-response-soap-envoloppe.xml");
mockServer.expect(payload(requestPayload)).andRespond(withSoapEnvelope(responseSoapEnvelope));
//init job
//myService call the webservice via WebServiceTemplate
myService.executeJob(job);
mockServer.verify();
//some asserts
}
}
So what I want to test is the soap action called. So I want something like this in my test class :
mockServer.expect(....withSoapAction("calledSoapAction")).andRespond(...
Creating your own RequestMatcher is pretty straightforward:
public class SoapActionMatcher implements RequestMatcher {
private final String expectedSoapAction;
public SoapActionMatcher(String expectedSoapAction) {
this.expectedSoapAction = SoapUtils.escapeAction(expectedSoapAction);
}
#Override
public void match(URI uri, WebServiceMessage request)
throws IOException, AssertionError {
assertThat(request, instanceOf(SoapMessage.class));
SoapMessage soapMessage = (SoapMessage) request;
assertThat(soapMessage.getSoapAction(), equalTo(expectedSoapAction));
}
}
Usage
mockServer.expect(connectionTo("http://server/"))
.andExpect(new SoapActionMatcher("calledSoapAction"))
.andRespond(withPayload(...)));

How to mock REST service response on the client side?

I would like to mock the RESTEasy client response in my JUnit tests with response body from the content in predefined xml-files. Consider following Person service client API and Person entity:
package my.company.com;
import java.net.URI;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlRootElement;
import org.apache.http.auth.AuthScope;
import org.apache.http.auth.Credentials;
import org.apache.http.auth.UsernamePasswordCredentials;
import org.apache.http.client.CookieStore;
import org.apache.http.client.protocol.ClientContext;
import org.apache.http.impl.client.BasicCookieStore;
import org.apache.http.impl.client.DefaultHttpClient;
import org.apache.http.protocol.BasicHttpContext;
import org.apache.http.protocol.HttpContext;
import org.jboss.resteasy.client.ClientRequest;
import org.jboss.resteasy.client.ClientResponse;
import org.jboss.resteasy.client.core.executors.ApacheHttpClient4Executor;
public class PersonServiceClient {
private final DefaultHttpClient httpClient;
public PersonServiceClient(String username, String password) {
Credentials credentials = new UsernamePasswordCredentials(username, password);
httpClient = new DefaultHttpClient();
httpClient.getCredentialsProvider().setCredentials(AuthScope.ANY, credentials);
}
public Person[] getPersons() throws Exception
{
URI url = new URI("http://www.mycompany.com/persons/");
Person[] persons = getByRest(url, Person[].class);
return persons;
}
private <T> T getByRest(URI url, Class<T> returnType) throws Exception {
ClientRequest client = createClientRequest(url.toString());
ClientResponse<T> response = client.get(returnType);
return response.getEntity();
}
private ClientRequest createClientRequest(String url) {
// Storing cookie to avoid creating new client for every call
CookieStore cookieStore = new BasicCookieStore();
HttpContext httpContext = new BasicHttpContext();
httpContext.setAttribute(ClientContext.COOKIE_STORE, cookieStore);
ApacheHttpClient4Executor clientExecutor = new ApacheHttpClient4Executor(httpClient, httpContext);
ClientRequest clientRequest = new ClientRequest(url, clientExecutor);
return clientRequest;
}
#XmlRootElement(name = "resource")
#XmlAccessorType(XmlAccessType.FIELD)
public class Person {
private String type;
private String name;
private String addres;
private String phone;
public String getType() {
return type;
}
public void setType(String type) {
this.type= type;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddres() {
return addres;
}
public void setAddres(String addres) {
this.addres = addres;
}
public String getPhone() {
return phone;
}
public void setPhone(String phone) {
this.phone = phone;
}
public Person() {
}
}
}
and the content of response-test1.xml:
<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<collection>
<resource>
<type>Peson</type>
<name>Christopher Monroe</name>
<addres>Wall Street 2</addres>
<phone>12345678</<phone>
</resource>
<resource>
<type>Person</type>
<name>John Dee</name>
<addres>Down town 2</addres>
<phone>2997562123</phone>
</resource>
</collection>
How can I mock the body of response in JUnit test below with content from response-test.xml file above?
#Test
public void testGetPersons() throws Exception{
PersonServiceClient client = new PersonServiceClient("joe", "doe");
Person[] persons = client.getPersons();
}
I tried to follow example in this post Is there a client-side mock framework for RESTEasy? but it doesn't show exactly how to select response body.
Consider using a factory to create the ClientRequest then mock the factory to return a mock of ClientRequest.
Rather than mocking the RESTEasy client, I'd suggest mocking the server using WireMock (disclaimer - I wrote it):
http://wiremock.org/
It's configurable via a fluent Java API from within JUnit and runs up an embedded web server which serves stubbed responses and permits you to verify the requests sent from your app.
I've written about the rationale for not mocking HTTP clients in a bit more detail here:
Introducing WireMock

Inject Spring bean within RESTEasy Resource at Test time

Within a Unit/Integration Test, I'm trying to use the RESTEasy embedded server TJWSEmbeddedJaxrsServer or POJOResourceFactory inorder to simulate through a MockHttpRequest.get("/data") a resource call for test purpose.
My problem is that based on the use of the server or the Resource factory I'm not able to have a non null instance of spring beans which are injected normally within my resources.
Here's some code for clarification, thanks in advance.
Spring application context :
<context:annotation-config />
<context:component-scan base-package="com.cdcfast.service" />
<bean id="simpleResource" class="com.cdcfast.rest.SimpleResource" />
SimpleResource.java :
#Component
#Path("/data")
#Produces(MediaType.APPLICATION_JSON)
#Consumes(MediaType.APPLICATION_JSON)
public class SimpleResource {
#Autowired
private SimpleService service;
#GET
#Produces(MediaType.APPLICATION_JSON)
public List<Data> getData() {
return MockDataBase.getInstance().getRows();
}
Unit Test :
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath*:/test/spring/testApplicationContext.xml" })
public class FakeTest {
private Dispatcher dispatcher;
#Before
public void before() {
dispatcher = MockDispatcherFactory.createDispatcher();
POJOResourceFactory noDefaults = new POJOResourceFactory(SimpleResource.class);
dispatcher.getRegistry().addResourceFactory(noDefaults);
}
#Test
public void aTestThatAlwaysPass() throws URISyntaxException {
MockHttpRequest request = MockHttpRequest.get("/data");
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
Assertions.assertThat(response.getStatus()).isEqualTo(HttpServletResponse.SC_OK);
Assertions.assertThat(response.getContentAsString()).isNotNull().isNotEmpty();
}
}
I've had this before because the RESTEasy factories create the POJO rather than Spring so they don't get wired up which can be worked around in the full container but is less easy in a test. The best way around this is to get a handle to your POJO once the factory creates it and then do something similar to this:
SpringBeanAutowiringSupport.processInjectionBasedOnCurrentContext(myPojo);
I personally ended up having Spring create the RESTEasy beans using the RESTEasy-Spring plugin and then launching my tests using Jetty, not sure if that is an option for you though.
I exeprienced same problem and i'have solved in similar way as James did:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = { "classpath:spring-context-test.xml" })
public class TestMyService {
Dispatcher dispatcher;
private String username = "user";
#Autowired
ApplicationContext context;
#Before
public void setUp() {
MyService g = new MyService(); //rest service with #autowired spring beans
context.getAutowireCapableBeanFactory().autowireBean(g);
dispatcher = MockDispatcherFactory.createDispatcher();
dispatcher.getRegistry().addSingletonResource(g);
}
#Test
public void TestRest() {
MockHttpRequest request;
try {
request = MockHttpRequest.get("/rest/service").header("LOGON_USER", username);
MockHttpResponse response = new MockHttpResponse();
dispatcher.invoke(request, response);
assertTrue("Error, unexpected status code: " + response.getStatus(), response.getStatus() == 200);
LoggerFactory.getLogger(this.getClass()).info("********** " + response.getContentAsString());
} catch (URISyntaxException e) {
Log.error(e.getMessage(), e);
fail(e.getMessage());
}
}
}