How to write integration tests for Rest Service API in spock - java

I have a Java class which contains API method
Ex:
#GET
#Path("/{id}")
public Resposce getIds(#PathParam(name) String name) {
//some code here
}
I want to right integration test for this API i.e while testing I want to call this method using path but not using method name

Have a look at Spring guides on their site:
Testing Web Layer

As you are explicitly asking for Spock: here is my standard implementation for an ApiSpec:
#SpringBootTest(webEnvironment = RANDOM_PORT)
abstract class AbstractServiceSpec extends Specification {
protected final static RestTestClient api = new RestTestClient()
#Value('http://localhost:${local.server.port}')
String serviceUrl
def setup() {
api.baseUrl = serviceUrl
}
def "GET /health should return 200"() {
expect:
api.get("/health").code() == 200
}
}
Note that RestTestClient is my own wrapper around OkHttp. You can use any HTTP client at hand of course.
The #SpringBootTest annotation makes Spring starting up the whole service. At the time your test gets executed, there service is fully up and running and you can black-box-test your API.
Generally Testing the Web Layer is a good read and most of it –as you can see in the example– can done in Spock as well as in JUnit.

This worked for me
import com.charter.aesd.testcommons.RESTSpecification
import groovyx.net.http.HttpResponseDecorator
class TestIT extends RESTSpecification{
def BASE_URL = "/test"
def "Get test"(){
when:
HttpResponseDecorator response = getRestClient().get([path:"$BASE_URL"+"/123"])
then:
response.status >=200 && response.status < 400
}
#Override
String getBaseUrl() {
return 'http://localhost:8889/'
}
}

Related

How do I test my service which is calling a 3 party rest endpoint?

I'm trying to test my service which is sending a rest request to a 3rd party rest endpoint which is mocked during the integration testing (Assume that I know the required Request Body). The code provided is only a rough outline of what I'm trying to achieve. The rest endpoint itself may not be available at all times, which is why I want to mock it. Let's look at the pseudo-code:
First my test case:
public class FooExampleTest {
private ExampleService exampleService;
#BeforeEach
void setup() {
exampleService = new ExampleService();
}
#Test
void example_TestCase() {
SomeEntity entity = new SomeEntity();
entity.setFoo("Foo!");
// set more fields....
// Calling the service containing the rest request to the 3rd party system
exampleService.sendToClient(entity);
}
}
The service containing the request to the 3rd party system is mocked
#Service
public class SomeServiceImpl {
// some fields
// ...
#Autowired
private RestTemplate restTemplate;
// ......
public void sendToClient(Entity entity){
var uri = "http://localhost:8080/foo"
var clientSystem = new ClientSystemRequest();
clientSystem.setImportField(entity)
log.info("Sending reqeust to client system");
restTemplate.postForObject(uri, clientSystem, ClientSystemResponse.class);
}
}
The 3rd party rest endpoint should be mocked during integration testing
#RestController
#Slf4j
/**
* Mocks the 3rd party rest endpoint
*/
public class 3rdPartyClientsystemResourceTest {
#PostMapping("/foo")
public ResponseEntity<?> foo(#RequestBody #Valid ClientSystemRequest clientSystemRequest){
log.info("Received, with data: {}", clientSystemRequest);
// Do some sort of validation....
return new ResponseEntity<>(HttpStatus.OK);
}
}
Have you looked into using mocking frameworks such as Mockito for example? You could then simply mock the restTemplate and only test the logic of your service rather than it's communication with API.
If you want an integration test than you must make the real call to the API. Otherwise it isn't an integration test.

Testing camel routes

I have multiple routes classes defined in my project under com.comp.myapp.routes.
For testing these I am mocking the end route and checking/comparing delivery received.
Say for example I have below routes:
public class MyRoute1 extends RouteBuilder {
public void configure() throws Exception {
//Route_1 code
}
}
public class MyRoute2 extends RouteBuilder {
public void configure() throws Exception {
//Route_2 code
}
}
....
...//some route impl
..
public class MyRouteN extends RouteBuilder {
public void configure() throws Exception {
//Route_N code
}
}
Now for all these routes the test case that I wrote seems same.
First mock it.
Mock for MyRoute1:
public class MyRoute1_Mock extends RouteBuilder {
public void configure() throws Exception {
from("direct:sampleInput")
.log("Received Message is ${body} and Headers are ${headers}")
.to("mock:output");
}
}
Test for MyRoute1:
public class MyRoute1_Test extends CamelTestSupport {
#Override
public RoutesBuilder createRouteBuilder() throws Exception {
return new MyRoute1_Mock();
}
#Test
public void sampleMockTest() throws InterruptedException {
String expected="Hello";
/**
* Producer Template.
*/
MockEndpoint mock = getMockEndpoint("mock:output");
mock.expectedBodiesReceived(expected);
String input="Hello";
template.sendBody("direct:sampleInput",input );
assertMockEndpointsSatisfied();
}
}
Now to make unit test for other classes just copy and paste the above code with different name say MyRoute2_Test , MyRoute3_Test , ...MyRouteN_Test.
So what did it actually tested?
It's just written for the purpose of writing test case.
It actually just checks/tests if mock library and camel-test library work or not Not our code works or not?
How should it actually be done?
You want to test your Camel routes but in the test you mock them away. So yes, you are testing your route mock instead of the real route.
To test your real routes:
Send a message to your real routes from endpoint
If this is not easy, mock your from endpoint (not the entire route!) by replacing it with a direct endpoint. This is quite easy with adviceWith
The test message is going through your route
Assert that any to endpoint receives the correct message by mocking these endpoints too. Again, use adviceWith for that. And Camel Mock of course
You can get the received messages (Exchanges) from a Camel Mock to do in depth assertions
If you got the happy test, start to write negative tests by injecting errors in your route. adviceWith can help here too
... and so on
If you are completely new to Camel route tests, get Camel in Action 2nd edition. It explains all mentioned testing aspects for Camel applications on 65 pages. And of course it also takes you on a complete ride through the Camel universe on much more pages.
By the way: if testing your routes is hard, they are too complex. Start to divide your routes so that they are easily testable.
The route you show doesn't really do anything to the messages traversing it, so testing that the same text you sent in one end comes out the other is all there is to test.
For routes with more data transformation and processing, you could test the output data types, that processors were called when needed, you could mock in throwing of exceptions, etc. What you have above is a good start on that.
Explained in-line,Hope this helps you understand significance of Mock in Unit Test:
public void sampleMockTest() throws InterruptedException {
String expected="Hello";
MockEndpoint mock = getMockEndpoint("mock:output");//Mocking endpoint
mock.expectedBodiesReceived(expected); //Setting expected output to mocked endpoint
String input="Hello";
template.sendBody("direct:sampleInput",input );//triggering route execution by sending input to route
assertMockEndpointsSatisfied(); //Verifies if input is equal to output
}
If your endpoint is Rest service you can make use of "TestRestTemplate" instead of Mocking it and Test like below:
import org.junit.runner.RunWith;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.test.context.junit4.SpringRunner;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleCamelApplicationTest {
}
import org.springframework.boot.test.web.client.TestRestTemplate;
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class SampleCamelApplicationTest {
#Autowired
private TestRestTemplate restTemplate;
}
#Test
public void sayHelloTest() {
// Call the REST API
ResponseEntity<String> response = restTemplate.getForEntity("/camel/hello", String.class);
assertThat(response.getStatusCode()).isEqualTo(HttpStatus.OK);
String s = response.getBody();
assertThat(s.equals("Hello World"));
}

How to test a Spring REST consumer with JUnit

I'm creating a Java Spring based microservice application that communicates using REST endpoints.
The app itself is so far has a simple structure: UI <-> DBLayer. The UI module is a api consumer and DBLayer is an api provider.
That being said I would like to test if my UI makes the correct REST calls using JUnit and/or Mockito. To be more specific, say I have a service class like this:
#Service
public class AuthorityService {
#Autowired
private RestTemplate restTemplate;
public Authority getAuthority(String authorityName) {
Authority authority =
restTemplate.getForObject(
"http://localhost:8080/authorities/" + authorityName,
Authority.class);
return authority;
}
}
In order to test this service method I would like to somehow verify that exactly this endpoint was called. Is there a way to wrap the service method and somehow assert a rest GET/POST/PUT etc. calls being made?
The desired test class should look something like this:
public class AuthorityServiceTest {
private AuthorityService authorityService = new AuthorityService();
#Test
public void getAuthorityTest(){
Assert.assertHttpGETCallMade(
authorityService.getAuthority("test"),
"http://localhost:8080/authorities/test");
}
}
You can use Mockito to inject the template, then verify the call.
#ExtendWith(MockitoExtension.class) // RunWith(MockitoJUnitRunner.class) for JUnit 4
public class AuthorityServiceTest {
#InjectMocks
private AuthorityService sut;
#Mock RestTemplate restTemplate;
#Test
public void getAuthorityTest(){
// mock rest call
Authority auth = mock(Authority.class);
when(restTemplate.getForObject(any(String.class), any(Class.class)).thenReturn(auth);
Authority result = sut.getAuthority("test");
// verify mock result was returned
assertSame(auth, result);
// verify call to rest template was performed
verify(restTemplate).getForObject(
"http://localhost:8080/authorities/test",
Authority.class);
}
}

How to test a Jersey rest service using mock objects

I have developed a rest service using Jersey. Now I want to write some integration tests for this web service but since not every class being used from the web service is already implemented I need to mock some of them. For example I have the following class:
public class A {
private String getWeather() {
return null;
}
}
My web service looks like this :
#Path("/myresource")
public class MyResource {
#GET
#Produces("text/plain")
public String getIt() {
A a = new A();
return a.getWeather();
}
}
The problem is that the getWeather function is not ready so I need to mock the return value for this function. But for the integration test where I issue a rest call I don't know how to do that.
Are there any ideas?
To make your design decoupled from A you should pass it in as a parameter to MyResource. Then you can easily mock it by hand or with mockito. With constructor injection it would look like this:
#Path("/myresource")
public class MyResource {
private A a;
public MyResource(A a) {
this.a = a;
}
#GET
#Produces("text/plain")
public String getIt() {
return a.getWeather();
}
}
and you can test it with
#Test
public void shouldGetIt() {
A a = mock(A.class);
when(a.getWeather()).thenReturn("sunny!");
MyResource r = new MyResource(a);
assertThat(r.getIt(), is("sunny!));
}
This makes your design decoupled. MyResource no longer depends on A directly but on anything that looks lik an A. Another benefit is that mockito doesn't mess with you class files. It is your code that is tested - not something that has been generated on the fly.
Many consider injection by constructor to be a bit old school. I am old so I like it.... With spring (a framework I don't recommend that you pick up) you can autowire variables like so:
#Autowire
private A a;
and you don't need the constructor at all. Spring will find a the only implementation of A and insert it in this variable. I prefer explicit programming so I would chose constructor injection any day.
You may be able to achieve this using Power Mockito (https://code.google.com/p/powermock/wiki/MockitoUsage)
#RunWith(PowerMockRunner.class)
#PrepareForTest({ MyResource.class })
public class MyResourceTest {
#Test
public void testGetIt()() {
MyResource mr = new MyResource();
//Setup mock
A mockA = PowerMockito.mock(A.class);
String mockReturn = "Some String";
//Stub new A() with your mock
PowerMockito.whenNew(A.class).withAnyArguments().thenReturn(mockA);
PowerMockito.doReturn(mockReturn).when(mockA).getWeather();
String ret = mr.getIt();
//asserts go here
}
}
Note that you can mock a local variable creation using PowerMockito's whenNew - this should take care of your concern for A a = new A() code in getIt() method.

Unit testing jersey Restful Services

I'm new to unit testing and I want to test some jersey services in a project. We are using Junit. Please guide me to write test cases in better way.
CODE:
#GET
#Path("/getProducts/{companyID}/{companyName}/{date}")
#Produces(MediaType.APPLICATION_JSON)
public Object getProducts(#PathParam("companyID") final int companyID,
#PathParam("date") final String date, #PathParam("companyName") final String companyName)
throws IOException {
return productService.getProducts(companyID, companyName, date);
}
Above mentioned service is working fine and I want to write junit test case to test above mentioned method. Above method will retrieve list of products (List<Product>) in JSON format. I would like to write test case to check response status and json format.
NOTE: We are using Jersey 1.17.1 version.
Help would be appreciated :)
For Jersey web services testing there are several testing frameworks, namely: Jersey Test Framework (already mentioned in other answer - see here documentation for version 1.17 here: https://jersey.java.net/documentation/1.17/test-framework.html) and REST-Assured (https://code.google.com/p/rest-assured) - see here a comparison/setup of both (http://www.hascode.com/2011/09/rest-assured-vs-jersey-test-framework-testing-your-restful-web-services/).
I find the REST-Assured more interesting and powerful, but Jersey Test Framework is very easy to use too. In REST-Assured to write a test case "to check response status and json format" you could write the following test (very much like you do in jUnit):
package com.example.rest;
import static com.jayway.restassured.RestAssured.expect;
import groovyx.net.http.ContentType;
import org.junit.Before;
import org.junit.Test;
import com.jayway.restassured.RestAssured;
public class Products{
#Before
public void setUp(){
RestAssured.basePath = "http://localhost:8080";
}
#Test
public void testGetProducts(){
expect().statusCode(200).contentType(ContentType.JSON).when()
.get("/getProducts/companyid/companyname/12345088723");
}
}
This should do the trick for you... you can verify JSON specific elements also very easily and many other details. For instructions on more features you can check the very good guide from REST-Assured (https://code.google.com/p/rest-assured/wiki/Usage). Another good tutorial is this one http://www.hascode.com/2011/10/testing-restful-web-services-made-easy-using-the-rest-assured-framework/.
HTH.
Just ignore the annotations and write a normal unit test that passes the required parameters. The return I thought would usually be of type "javax.ws.rs.core.Response" ... There is a getEntity() method on that can be used. Using a Mock object framework like Mockito could be helpful in this case too.
Are you familiar with Chapter 26. Jersey Test Framework?
public class SimpleTest extends JerseyTest {
#Path("hello")
public static class HelloResource {
#GET
public String getHello() {
return "Hello World!";
}
}
#Override
protected Application configure() {
return new ResourceConfig(HelloResource.class);
}
#Test
public void test() {
final String hello = target("hello").request().get(String.class);
assertEquals("Hello World!", hello);
}
}

Categories

Resources