I am learning to implement web service using JAX-RS and JAXB, however I couldn't get this to work. The idea is to have a web service that can create a customer(with customer name) and store them in a Hash Map. I tried to create test as well but the test failed with error
javax.ws.rs.ProcessingException: Unable to invoke request
at org.jboss.resteasy.client.jaxrs.engines.ApacheHttpClient4Engine.invoke
(ApacheHttpClient4Engine.java:287)at
org.jboss.resteasy.client.jaxrs.internal.ClientInvocation.invoke
(ClientInvocation.java:407)
at org.jboss.resteasy.client.jaxrs.internal.ClientInvocationBuilder.post
(ClientInvocationBuilder.java:195)
at BloggerTest.addCustomer(StoreTest.java:65)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
The Failure Trace says `Caused by :javax.ws.rs ProcessingException:
could not find writer for content-type application/xml type: store.domain.Customer
which I don't quite understand.
So below is what I have got at the moment, I'm using the "return singletons" to create instance of the store class:
A Store class:
public class Store {
private Map<String, Customer> _customer;
public Store() {
_customer = new ConcurrentHashMap <String,Customer>();
}
//assume the incoming http request contains customer name
#Post
#Consumes("application/xml")
public Response createCustomer (Customer customer){
_customer.put(customer.getName(), customer);
return Response.created( URI.create("/customers/" + customer.getName()))
.build();
}
}
And a class that runs test:
public class StoreTest {
private static final String WEB_SERVICE_URI = "http://localhost:10000/services/store";
private static Client _client;
#BeforeClass
public static void setUpClient() {
_client = ClientBuilder.newClient();
}
#Before
public void reloadServerData() {
Response response = _client
.target(WEB_SERVICE_URI).request()
.put(null);
response.close();
try {
Thread.sleep(10);
} catch (InterruptedException e) {
}
}
#AfterClass
public static void destroyClient() {
_client.close();
}
#Test
public void addCustomer() {
Customer BartSimpsons = new Customer ("BartSimpsons");//create a new customer with name
Response response = _client
.target(WEB_SERVICE_URI).request()
.post(Entity.xml(BartSimpsons));
String location = response.getLocation().toString();
response.close();
Customer BartCreated = _client.target(location).request()
.accept("application/xml").get(Customer.class);
//check if the Customer created by the service has the same name with the original customer
assertEquals(BartSimpsons.getName(), BartCreated.getName());
}
}
I feel that I am missing some important points here, but I really couldn't figure how what I did wrong with the annotations or something else. Can someone please help? Many thanks in advance!
I also faced the same problem. Using #Produces annotation over my service method helped me to resolve the problem. Hope this will help you.
Related
I do want to write some functional tests for our project. Techstack: Play Framework 1.5, Java 16, Junit 3.
I found following documentation:
test - 1.5.x
security - 1.5.x
So the Controller looks something like this.
#AllowFeature(Feature.SEARCH_BOX)
public static void search(String term) {
//implementation omitted
TablePage<MyAwesomeType> page = search(term);
render(..., page, term);
}
And my test looks like this
public class SearchTest extends FunctionalTest {
#Test
public void search_withResults() {
String term = "ABC";
Http.Response response = GET("/foo/search?term=" + term);
assertStatus(302, response);
assertThat(renderArgs("page"), is(notNullValue()));
TablePage<MyAwesomeType> page = (TablePage<MyAwesomeType>) renderArgs("page");
assertTrue(page.getTotalRecords() >= 1);
}
}
However, the TablePage<MyAwesomeType> page is null when it really should not be, and i am unable to step into the controller method with the debugger. So it looks like the controller method search(...) is not called at all.
The response Code is 302 - Found but I think this might be play suggestion it found the path /foo/search
My guess is that i need to setup some UserContext or send a authenticityToken along with the request. So play can check the required feature #AllowFeature(Feature.A_SEARCH_BOX).
Does anybody know how I would setup such a functional test?
Any help is appreciated. Thanks!
I was able to figure this out.
I need to log into the application and then the play FunctionalTest.class takes care of the cookie.
Add #NoAuthenticityto the login method
#NoAuthenticity // <-- This enables execution without authenticityToken
public static void login(#Required String username, #Required String password) {
...
}
Post a request to login before the test.
#Test
public void search_withResults() {
// 1. login
Map<String, String> credentials = Map.of("username", "MyUsername", "password", "MyPassword");
POST("/login", credentials);
// Note: session info / authenticityToken is stored in a cookie
// FunctionalTest.class makes sure to use this cookie for subsequent requests
// This request now works like a charm
String term = "ABC";
Http.Response response = GET("/foo/search?term=" + term);
assertStatus(302, response);
assertThat(renderArgs("page"), is(notNullValue()));
TablePage<MyAwesomeType> page = (TablePage<MyAwesomeType>) renderArgs("page");
assertTrue(page.getTotalRecords() >= 1);
}
Note: One can use the JUnit #Before Annotation to simplify the test class.
#Before
public void login(){
Map<String, String> credentials = Map.of("username", "MyUsername", "password", "MyPassword");
POST("/login", credentials);
}
#Test
public void search_withResults() {
String term = "ABC";
Http.Response response = GET("/foo/search?term=" + term);
assertStatus(302, response);
assertThat(renderArgs("page"), is(notNullValue()));
TablePage<MyAwesomeType> page = (TablePage<MyAwesomeType>) renderArgs("page");
assertTrue(page.getTotalRecords() >= 1);
}
#Test
public void anotherTest() { ... }
#Test
public void yetAnotherTest() { ... }
In my spring boot project, one of my Service depends on external service like Amazon. I am writing the integration testing of the Controller classes. So, I want to mock the method in the AmazonService class(as it depends on third party API). The method is void with a single Long argument and can throw a custom application-specific exceptions.
The method is as follows:-
class AmazonService{
public void deleteMultipleObjects(Long enterpriseId) {
String key = formApplicationLogokey(enterpriseId,null);
List<S3ObjectSummary> objects = getAllObjectSummaryByFolder(key);
List<DeleteObjectsRequest.KeyVersion> keys = new ArrayList<>();
objects.stream().forEach(object->keys.add(new DeleteObjectsRequest.KeyVersion(object.getKey())));
try{
DeleteObjectsRequest deleteObjectsRequest = new DeleteObjectsRequest(this.bucket).withKeys(keys);
this.s3client.deleteObjects(deleteObjectsRequest);
log.debug("All the Application logos deleted from AWS for the Enterprise id: {}",enterpriseId);
}
catch(AmazonServiceException e){
throw new AppScoreException(AppScoreErrorCode.OBJECT_NOT_DELETED_FROM_AWS);
}
}}
class Test
class Test
{
#Autowired
AmazonServiceImpl amazonService;
#Autowired
EnterpriseService enterpriseService;
#Before
public void init()
{
amazonService = Mockito.mock(AmazonServiceImpl.class);
Mockito.doNothing().when(amazonService).deleteMultipleObjects(isA(Long.class));
}
#Test
public void testDeleteEnterprise(){
setHeaders();
EnterpriseDTO enterpriseDTO = createEnterpriseEntity(null,"testDeleteEnterpriseName3",null,null,null);
String postUrl = TestUrlUtil.createURLWithPort(TestConstants.ADD_ENTERPRISE,port);
HttpEntity<EnterpriseDTO> request1 = new HttpEntity<>(enterpriseDTO,headers);
ResponseEntity<EnterpriseDTO> response1 = restTemplate.postForEntity(postUrl,request1,EnterpriseDTO.class);
assert response1 != null;
Long enterpriseId = Objects.requireNonNull(response1.getBody()).getId();
String url = TestUrlUtil.createURLWithPort(TestConstants.DELETE_ENTERPRISE,port)+File.separator+enterpriseId;
HttpEntity<EnterpriseDTO> request = new HttpEntity<>(null, headers);
ResponseEntity<Object> response = restTemplate.exchange(url,HttpMethod.DELETE,request,Object.class);
Assert.assertEquals(Constants.ENTERPRISE_DELETION_SUCCESS_MESSAGE,response.getBody());
}
}
class EnterpriseResource
class EnterpriseResource
{
#DeleteMapping("/enterprises/{enterpriseId}")
public ResponseEntity<Object> deleteEnterprise(#PathVariable Long enterpriseId) {
log.debug("REST request to delete Enterprise : {}", enterpriseId);
enterpriseService.delete(enterpriseId);
return ResponseEntity.badRequest().body(Constants.ENTERPRISE_DELETION_SUCCESS_MESSAGE);
}
}
class EnterpriseServiceImpl
class EnterpriseServiceImpl
{
#Override
public void delete(Long enterpriseId) {
log.debug("Request to delete Enterprise : {}", enterpriseId);
enterpriseRepository.deleteById(enterpriseId);
amazonService.deleteMultipleObjects(enterpriseId);
}
}
I have tried various approaches to Mock this method but it didn't work and control is going inside this method during debugging. I want to do nothing in this method during testing.
I have tried the various approaches like throw(), doNothing(), spy() etc.
Please help what is missing here?
Thanks
I'm trying to make a get request from Play Framework to another server and save the response body in database. All the answers to similar questions show how to send retrieved data through controller action. But I want to make a request from actor and save the response in DB.
Here is the code of Actor class:
public class TestActor extends UntypedActor {
#Inject
WSClient ws;
#Inject
ExecutionContextExecutor exec;
public static Props props = Props.create(TestActor.class);
public int i = 0;
#Override
public void onReceive(Object msg) throws Exception {
if (msg instanceof String && msg == "doTest") {
Logger.info("I am doing test " + ++i);
CompletionStage<JsonNode> jsonPromise = ws.url("http://localhost:3000").get().thenApply(WSResponse::asJson);
}
}
}
I don't understand how to process that jsonPromise further. Any help would be appreciated.
I'm trying to find some manual how to test POST methods using jersey framework, only got examples for GET method.
Here's example:
#POST
#Path("add")
#Consumes(MediaType.APPLICATION_XML)
#Produces(MediaType.APPLICATION_XML)
public Response addUser(JAXBElement<User> user) {
int code = userService.addUser(user.getValue());
if (code == 500) {
return Response.status(500).build();
}
return Response.status(code).entity(user).build();
}
Could you please post some POST method test example?
Thank you in advance.
After research I did it!
Here's my solution, it works just fine.
And it's rather integration test, but we can write unit tests in similar manner.
public class RestTest extends JerseyTest{
#Override
protected Application configure() {
return new Your_Resource_Config(); //Your resource config with registered classes
}
//#Before and/or #After for db preparing etc. - if you want integration tests
#Test
public void addUserTest() {
User user = new User();
user.setEmail("user2#mail.com");
user.setName("Jane Doe");
user.getUserRoles().getRoles().add("supertester");
Entity<User> userEntity = Entity.entity(user, MediaType.APPLICATION_XML_TYPE);
target("users/add").request().post(userEntity); //Here we send POST request
Response response = target("users/find").queryParam("email", "user2#mail.com").request().get(); //Here we send GET request for retrieving results
Assert.assertEquals("user2#mail.com", response.readEntity(User.class).getEmail());
}
I am developing a simple RESTFul service using JBoss-7.1 and RESTEasy.
I have a REST Service, called CustomerService as follows:
#Path(value="/customers")
#ValidateRequest
class CustomerService
{
#Path(value="/{id}")
#GET
#Produces(MediaType.APPLICATION_XML)
public Customer getCustomer(#PathParam("id") #Min(value=1) Integer id)
{
Customer customer = null;
try {
customer = dao.getCustomer(id);
} catch (Exception e) {
e.printStackTrace();
}
return customer;
}
}
Here when I hit the url http://localhost:8080/SomeApp/customers/-1 then #Min constraint will fail and showing the stacktrace on the screen.
Is there a way to catch these validation errors so that I can prepare an xml response with proper error message and show to user?
You should use exception mapper. Example:
#Provider
public class ValidationExceptionMapper implements ExceptionMapper<javax.validation.ConstraintViolationException> {
public Response toResponse(javax.validation.ConstraintViolationException cex) {
Error error = new Error();
error.setMessage("Whatever message you want to send to user. " + cex);
return Response.entity(error).status(400).build(); //400 - bad request seems to be good choice
}
}
where Error could be something like:
#XmlRootElement
public class Error{
private String message;
//getter and setter for message field
}
Then you'll get error message wrapped into XML.