How to write Junit Test Cases in springBoot? - java

Thid is my mapping from my controller class , now I want to write unit test case for the same
#GetMapping(value = "/tokenSearch/{id}/{name}/{values}/{data_name}", produces = MediaType.APPLICATION_JSON_VALUE)
public ResponseEntity<String> getValuesfromToken(
throws ClientProtocolException, IOException, ParseException {
ResponseEntity<String> data = elasticService.getData();
return data;
}
this is what I was trying but its asking for castargument for Result matcher, getting error , can someone pls help me with this
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
public class ElasticCaseTests extends Mockito {
#Autowired
private MockMvc mockMvc;
#Test
public void testGetValuesfromToken() throws Exception {
String contentAsString = mockMvc.perform(get("/tokenSearch/1/PRODUCT/PRODUCT/189")).andExpect(status().isOk())
.andExpect(jsonPath("$.id", is("1"))).andExpect(jsonPath("$.name", is("product")))
.andExpect(jsonPath("$.values", is("product")))
.andExpect(jsonPath("$.searching_word", is("189"))).andExpect(status().isOk()).andReturn().getResponse()
.getContentAsString();
}
java.lang.AssertionError: No value at JSON path "$.id"' , can someone help me with this

This could be one example:
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment=WebEnvironment.RANDOM_PORT)
#AutoConfigureMockMvc
class ControllerTest {
#Autowired
private MockMvc mockMvc;
#Test
void testGetValuesfromToken() throws Exception {
this.mockMvc
.perform(get("/tokenSearch/............."))
.andExpect(status().isOk())
.andExpect(jsonPath("$.hierarchy_name"").value(".....what you expect..."))
.andDo(print());
}

See example it may help
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import ….services.AuthorizationService;
import ….AuthorizationRequest;
import ….AuthorizationResponse;
import java.time.Clock;
import java.time.Instant;
import java.time.ZoneId;
import org.junit.Before;
import org.junit.Test;
public class MyControllerTest {
AuthorizationService authorizationService;
AuthorizationController controller;
private Clock clock;
#Before
public void setUp() throws Exception {
clock = Clock.fixed(Instant.now(), ZoneId.systemDefault());
authorizationService = mock(AuthorizationService.class);
controller = new AuthorizationController(authorizationService);
}
#Test
public void createJws() throws Exception {
when(authorizationService.createJws(any(AuthorizationRequest.class)))
.thenReturn(new AuthorizationResponse());
AuthorizationRequest authorizationRequest =
AuthorizationRequest.builder().id(“abc”).build();
AuthorizationResponse jwsResponse =
controller.createJws(authorizationRequest);
verify(authorizationService).createJws(authorizationRequest);
}
}

I usually write my Controller tests more or less like this. If you want to test the json output and status correctness, you could implement a helper method like asJsonString and see if everything is proper. Maybe you find this approach helpful.
#WebMvcTest
#ContextConfiguration(classes = {ResourceController.class})
class ResourceControllerTest {
private final String JSON_CONTENT_TYPE = "application/json";
#Autowired
private MockMvc mockMvc;
#MockBean
private ElasticService elasticService;
#Test
public void shouldReturnProperData() throws Exception {
String data = "some returned data"; // format it properly, as elasticService would
YourJsonObject objectToReturn = new YourJsonObject(...);
when(elasticService.getData()).thenReturn(data);
mockMvc.perform(post("/tokenSearch/1/PRODUCT/PRODUCT/189").contentType(JSON_CONTENT_TYPE).content(asJsonString(email)))
.andDo(print())
.andExpect(status().isOk())
.andExpect(content().string(asJsonString(objectToReturn)));
}
}
private String asJsonString(final Object obj) {
try {
return new ObjectMapper().writeValueAsString(obj);
} catch (Exception e) {
throw new RuntimeException(e); // delete this exception conversion if you will :)
}
}
}
The most important is though to test if elasticService returns the proper data so you can implement the unit tests there. Here, you can test statuses, paths, and slightly the json outlook, but these are not any kind of amazing tests.

Related

Mockito thenThrow cannot be catch

I am using Mockito to mock the method of service layer.
This is my test code.
#InjectMocks
MyServiceImpl myServiceImpl;
#Mock
MyDAO myDAO;
#Rule
public ExpectedException exceptionRule = ExpectedException.none();
#Test
public void getAllFail(){
Mockito.when(myDAO.getAll().thenThrow(new DataException("mock"));
exceptionRule.expect(ServiceException.class);
myServiceImpl.getAllData();
}
service code
#Service
public class myServiceImpl extends myService{
private final MyDAO myDAO;
...
#Override
public List getAllData(){
try{
return myDAO.getAll();
} catch (DataException exception){
throw new ServiceException("exception");
}
}
}
At first I thought that by mocking DAO class to throw exception, it would be caught by catch and turn into ServiceException but the result was
java.lang.AssertionError:
Expected an instance of com.example.exception.ServiceException
but: <com.example.exception.DataException: mock> is a com.example.exception.DataException
How can I test exception of my service in this case? Please guide me. Thank you in advance.
I think you need to use Assertions.assertThrows when you are expecting an exception from a method call and you need chain the exception properly. Here is how I have done it.
Service class with exceptions and method calls
import org.springframework.stereotype.Service;
import java.util.Collections;
import java.util.List;
#Service
public class SampleTestService {
private final MyDao myDao;
public SampleTestService(MyDao myDao) {
this.myDao = myDao;
}
public List<String> getData() {
try {
return myDao.getStringList();
} catch (MyDao.DataException dataException) {
throw new ServiceException("Error getting data");
}
}
static class ServiceException extends RuntimeException {
public ServiceException(String message) {
super(message);
}
}
}
class MyDao {
public List<String> getStringList() {
return Collections.emptyList();
}
static class DataException extends RuntimeException {
public DataException(String message) {
super(message);
}
}
}
Unit Test class in action
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.util.Arrays;
import java.util.List;
#ExtendWith(SpringExtension.class)
class SampleTestServiceTest {
// private final MyDao myDao = mock(MyDao.class);
#Mock
MyDao myDao;
#Test
void testDaoThrowsException() {
Mockito.when(myDao.getStringList()).thenThrow(new MyDao.DataException("Error connecting to database"));
SampleTestService sampleTestService = new SampleTestService(myDao);
Assertions.assertThrows(SampleTestService.ServiceException.class,
() -> {
sampleTestService.getData();
});
}
#Test
void testDaoReturnData() {
List<String> colors = Arrays.asList("red", "green", "blue");
Mockito.when(myDao.getStringList()).thenReturn(colors);
SampleTestService sampleTestService = new SampleTestService(myDao);
List<String> data = sampleTestService.getData();
Assertions.assertEquals(3, data.size());
Assertions.assertSame(data, colors);
}
}

Testing Apache Camel servlet with spring cloud contract

I have a spring boot application with routes defined as follows:
#Component
public class SampleRoute extends RouteBuilder {
#Override
public void configure() throws Exception {
rest("/customers-controller/")
.get("/customers").to("direct:getcustomer)
.get("/{id}").to("direct:customerDetail")
.get("/{id}/orders").to("direct:customerOrders")
.post("/neworder").to("direct:customerNewOrder");
}
I'm trying to create a contract to test this endpoint ('/customers') and create a stub that will be used in my consumer class.
A contract for messaging services like camel is similar to this:
Contract.make {
label("positive")
input {
messageFrom("seda:getcustomer")
messageBody([
id: "25_body"
])
messageHeaders {
messagingContentType(applicationJson())
// header("id","123_header")
}
}
outputMessage {
sentTo("seda:iris-address-int")
body([
"id":"25_body","firstname":null,"lastname":null,"email":null,"phone":null,"street":null,"city":null,"postcode":null
]
)
headers {
messagingContentType()
}
}
}
Now, I'm not sure on how to define the contract such that it points to my chosen rest endpoint like I would do with a RestController.
Consider the test below. Is it possible to generate this test on the provider side using spring cloud contract given that I'm not using the #RestController but rather the rest component ?
#RunWith(CamelSpringBootRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class TestRestRoute {
#Autowired
private TestRestTemplate restTemplate;
#LocalServerPort
int randomServerPort
#Test
public void test_bank_route() throws URISyntaxException, IOException {
//call the REST API
final String baseUrl = "http://localhost:" + randomServerPort + "/customers-controller/customers";
URI uri = new URI(baseUrl);
ResponseEntity<String> response = restTemplate.getForEntity(uri, String.class );
Assert.assertEquals(MediaType.APPLICATION_JSON_VALUE, Objects.requireNonNull(response.getHeaders().getContentType()).toString());
Assert.assertEquals(200, response.getStatusCodeValue());
Assert.assertNull(response.getBody());
}
With this commit https://github.com/spring-cloud-samples/spring-cloud-contract-samples/commit/760d7105bde2f253ca0bff84fa3f4d5a35a1931e I've added a sample for Camel to spring cloud contract branch 3.0.x. Of course same rules apply to Spring Cloud Contract in other versions. In general what you can do is on the producer side:
Define a configuration for a route and extract the component URIs to separate methods:
#Configuration
class RouteConfiguration {
#Bean
RoutesBuilder myRouter() {
return new RouteBuilder() {
#Override
public void configure() {
from(start())
.bean(MyProcessor.class)
.to(finish());
}
};
}
// rabbitmq://hostname[:port]/exchangeName?[options]
String start() { return "rabbitmq:localhost/person?queue=person"; }
String finish() {
return "rabbitmq:localhost/verifications?queue=verifications";
}
}
However in the contract we will leverage the seda component (the way you did it)
Contract.make {
label("positive")
input {
messageFrom("seda:person")
messageBody([
age: 25
])
messageHeaders {
messagingContentType(applicationJson())
}
}
outputMessage {
sentTo("seda:verifications")
body([
eligible: true
])
headers {
messagingContentType(applicationJson())
}
}
}
Now, in the base class for the generated tests we will change the configuration to reflect what we have in the contract
package com.example.demo;
import org.apache.camel.test.spring.CamelSpringRunner;
import org.junit.runner.RunWith;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.verifier.messaging.boot.AutoConfigureMessageVerifier;
import org.springframework.context.annotation.Configuration;
import org.springframework.test.annotation.DirtiesContext;
#RunWith(CamelSpringRunner.class)
#SpringBootTest(classes = BaseClass.TestConfiguration.class)
// IMPORTANT
#AutoConfigureMessageVerifier
// IMPORTANT
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public abstract class BaseClass {
#Configuration
#EnableAutoConfiguration
static class TestConfiguration extends RouteConfiguration {
// was: rabbit
// will be: a queue
#Override
String start() {
return "seda:person";
}
#Override
String finish() {
return "seda:verifications";
}
}
}
We're overriding the start() and finish() methods. You could do sth similar in your case. Then on the consumer side you can reference it like this:
import com.fasterxml.jackson.databind.ObjectMapper;
import org.apache.camel.CamelContext;
import org.apache.camel.ConsumerTemplate;
import org.apache.camel.ProducerTemplate;
import org.assertj.core.api.BDDAssertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.cloud.contract.stubrunner.spring.AutoConfigureStubRunner;
import org.springframework.cloud.contract.stubrunner.spring.StubRunnerProperties;
import org.springframework.test.annotation.DirtiesContext;
#SpringBootTest
#AutoConfigureStubRunner(
ids = "com.example:beer-api-producer-camel",
stubsMode = StubRunnerProperties.StubsMode.LOCAL
)
// IMPORTANT
#DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
public class DemoApplicationTests {
#Autowired ConsumerTemplate consumerTemplate;
#Autowired ProducerTemplate producerTemplate;
#Autowired CamelContext camelContext;
ObjectMapper objectMapper = new ObjectMapper();
// consumer -> seda:person
// producers -> seda:person -> person -> verifications -> seda:verifications
// consumer -> seda:verifications
#BeforeEach
public void setup() {
this.camelContext.getShutdownStrategy().setTimeout(1);
}
#Test
public void should_trigger_a_negative_verification() throws Exception {
this.producerTemplate.sendBodyAndHeader("seda:person", new Person(17),
"contentType", "application/json");
String string =
this.consumerTemplate.receiveBody("seda:verifications", String.class);
Verification verification = this.objectMapper.readerFor(Verification.class).readValue(string);
BDDAssertions.then(verification).isNotNull();
BDDAssertions.then(verification.eligible).isFalse();
}
#Test
public void should_trigger_a_positive_verification() throws Exception {
this.producerTemplate.sendBodyAndHeader("seda:person", new Person(25),
"contentType", "application/json");
String string =
this.consumerTemplate.receiveBody("seda:verifications", String.class);
Verification verification = this.objectMapper.readerFor(Verification.class).readValue(string);
BDDAssertions.then(verification).isNotNull();
BDDAssertions.then(verification.eligible).isTrue();
}
}

mockito when interact with each other in different method

I have a short piece of code and two unit test. Strangely when I launch the test separately they works well but when I launch them together it look like the second method use the "when" of the first method.
Tested method :
public ProductIssuer update(ProductIssuer productIssuer) {
findById(productIssuer.getId())
.orElseThrow(() -> new B4FinanceException(ErrorCode.USER_NOT_FOUND, "Please provide an existing user"));
return productIssuerRepository.save(productIssuer);
}
The tests :
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class ProductIssuerServiceTest {
#InjectMocks
private static ProductIssuerService productIssuerService;
#Mock
private static ProductIssuerRepository productIssuerRepository;
public static final UUID DEFAULT_UUID = UUID.fromString("b8fc499a-2084-11e8-b467-0ed5f89f0000");
private static final String DEFAULT_NAME = "productIssuer Name";
#BeforeEach
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void updateNotFoundThrowException() {
ProductIssuer productIssuer = new ProductIssuer();
productIssuer.setName(DEFAULT_NAME);
when(productIssuerRepository.findById(any())).thenReturn(Optional.empty());
assertThatExceptionOfType(B4FinanceException.class).isThrownBy(() -> productIssuerService.update(productIssuer));
}
#Test
public void update() {
ProductIssuer productIssuer = new ProductIssuer();
productIssuer.setName(DEFAULT_NAME);
productIssuer.setId(DEFAULT_UUID);
when(productIssuerRepository.findById(any())).thenReturn(Optional.of(productIssuer));
when(productIssuerRepository.save(any())).thenReturn(productIssuer);
productIssuerService.update(productIssuer);
}
}
The result is ok for the first test (updateNotFoundThrowException) but for the second test I got a "Please provide an existing user" error.

How to mock returned object from inner method on some other class in java

I read at least 20 posts but still couldn't find the answer. So, posting this question. May be it is answered in some other post, which I couldn't find.
class OuterService {
InnerService innerService;
#Autowired
public void setInnerService(InnerService innerService){
this.innerService = innerService;
}
public void method() {
List<C> listOfC = new ArrayList<C>();
C c = new C();
c.setUserProfiles(someObject);
c = innerService.invokeMethod(String str1,Map map,
String str2, Object obj1, String str3, String str4,
C c, String str5);
c.setCreatedDate(some String value); // Here c comes null while executing jUnits.
listOfC.add(c);
}
}
Here is my Test class:
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Matchers;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.MockitoAnnotations;
import org.mockito.junit.MockitoJUnitRunner;
import com.pogo.service.DeviceRegistrationService;
#SuppressFBWarnings("RV_RETURN_VALUE_IGNORED_NO_SIDE_EFFECT")
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
class ClassOuterServiceTest {
#InjectMocks
OuterService outerService;
#Mock
InnerService innerService;
#Mock C c;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
outerService.setInnerService(innerService);
}
#Test
public void methodTest() {
when(innerService.invokeMethod(Mockito.anyString(),
Mockito.any(Map.class), Mockito.anyString(),Mockito.anyString(),
Mockito.any(PersonSessionToken.class), Mockito.anyString(),Mockito.anyString(), Mockito.anyString(),
Mockito.any(RequestHeader.class),Mockito.any(C.class),
Mockito.anyString() )).thenReturn(c);
doNothing().when(c).invokeCMethod();
outerService.method();
}
}
But I get null inside object c in OuterService.java. Also if I use Matchers.any() or Matchers.anyString() in invokeMethod() then , it shows Matchers exception.
What is the appropriate solution?
You don't need to create the object for OuterService use #InjectMocks annotation and when you use method stubbing use mock objects only. In your program you are creating object for c. Instead of creating object just use #Mock annotation.
When you using Mockito.any() mention the class inside parenthesis. Mockito.any(C.class) like this.
Don't use PowerMockRunner unless you are testing static or final classes.
#SpringBootTest
#RunWith(MockitoJUnitRunner.class)
public class ClassOuterServiceTestC {
#Mock
public InnerService innerService;
#InjectMocks
public OuterService outerService;
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
#Test
public void methodTest() {
C obj = mock(C.class);
when(innerService.invokeMethod(anyString(), anyMap(), anyString(), any(), anyString(), anyString(), any(TestC.class), anyString()))
.thenReturn(obj);
doNothing().when(obj).setUserProfiles(any(Object.class));
doNothing().when(obj).setCreatedDate(anyString());
outerService.method();
}
}

How apply different configurations per method in Spring Boot test class?

I have an annotation that pulls in some configurations (via #Import). I want to test running with and without that annotation. I want to do this in one test class.
I know that I can change the spring context per method #DirtiesContext(classMode = BEFORE_EACH_TEST_METHOD), but I don't know how to have it run with or without the annotation on different methods.
How would I achieve this?
What I want to do:
package com.test.reference.cors;
import com.test.EnableCors;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.MvcResult;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.client.RestTemplate;
import org.springframework.web.context.WebApplicationContext;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.options;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
#RunWith(SpringJUnit4ClassRunner.class)
#WebMvcTest(secure = false)
#ContextConfiguration(classes = {ControllerConfig.class, ReferenceController.class})
public class TestCORS
{
private MockMvc mockMvc;
private ObjectMapper objectMapper;
#Autowired
private RestTemplate restTemplate;
#Autowired
private WebApplicationContext webApplicationContext;
#Before
public void setup()
{
//Create an environment for it
mockMvc = MockMvcBuilders.webAppContextSetup(this.webApplicationContext)
.dispatchOptions(true).build();
//Create our marshaller
objectMapper = new ObjectMapper();
}
#Test
public void testWithoutCors() throws Exception
{
//Call to test a date
MvcResult result = mockMvc.perform(
options("/v1/testdate")
.contentType(MediaType.APPLICATION_JSON)
//CORS HEADERS
.header("Access-Control-Request-Method", "DELETE")
.header("Origin", "https://evil.com")
).andExpect(status().isForbidden())
.andReturn();
}
#Test
#EnableCors
public void testWithCors() throws Exception
{
//Call to test a date
MvcResult result = mockMvc.perform(
options("/v1/testdate")
.contentType(MediaType.APPLICATION_JSON)
//CORS HEADERS
.header("Access-Control-Request-Method", "POST")
.header("Origin", "http://evil.com")
).andExpect(status().isOk())
.andReturn();
}
}
Using nested classes, you could do something like this:
class NewFeatureTest {
#SpringBootTest
protected static class NewFeatureWithDefaultConfigTest {
#Autowired
ApplicationContext context;
#Test
void yourTestMethod() {
}
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
protected static class Config {
// your 1st config
}
}
#SpringBootTest
protected static class NewFeatureWithDefaultsTests {
#Autowired
ApplicationContext context;
#Test
void yourOtherTestMethod() {
}
#Configuration(proxyBeanMethods = false)
#EnableAutoConfiguration
protected static class NoDefaultsConfig {
// your 2nd config
}
}}

Categories

Resources