I am new to web services and spring boot. I have written a service for which I am now writing a test case.
My application gets Soap request, parses the body and saves contents into database.
My test case tests this service.
When I run the application and send a request from Postman, it runs alright. But when I call my service method from test case, I get nullpointer for JaxBcontext.
I have declared Jaxbcontext in my AppConfig.java (which is annotated with #Configuration and my jaxb is a bean with #Bean annotation) in my service, I have #autowire to use jaxbcontext.
I have pasted code snippets for clarity. Please advise me what I am doing wrongly here.
My test case
public class ReferralExchangeEndpointTest {
ReferralExchangeEndpoint referralExchangeEndpoint = new ReferralExchangeEndpoint();
JAXBContext jbcTest;
Marshaller marshaller;
Unmarshaller unmarshaller;
public ReferralExchangeEndpointTest() throws JAXBException {
}
#Before
public void setUp() throws Exception {
jbcTest = JAXBContext.newInstance(
"our app schema"); // this is working fine, I have replaced schema with this text for posting it in stack.
ObjectFactory factory = new ObjectFactory();
marshaller = jbcTest.createMarshaller();
unmarshaller = jbcTest.createUnmarshaller();
}
#Test
public void send() throws Exception {
File payload = new File("payload.xml");
Object x = unmarshaller.unmarshal(payload);
JAXBElement jbe = (JAXBElement) x;
System.out.println(jbe.getName());
Object test = jbe.getValue();
SendRequestMessage sendRequestMessage = (SendRequestMessage) jbe.getValue();
// Method in test.
referralExchangeEndpoint.send(sendRequestMessage);
}
}
My service class
#Endpoint
public class ReferralExchangeEndpoint {
public static final Logger logger = LoggerFactory.getLogger(ReferralExchangeEndpoint.class);
#Autowired
private JAXBContext jaxbContext;
#Autowired
.
.
.
private Form parseBody(String payLoadBody) {
try {
Unmarshaller um = jaxbContext.createUnmarshaller();
return (Form) um.unmarshal(new StringReader(payLoadBody));
} catch (Exception e) {
throw new RuntimeException("Failed to extract the form from the payload body", e);
}
}
My appconfig file
#Configuration
public class AppConfig {
#Bean
public JAXBContext jaxbContext() throws JAXBException {
return
JAXBContext.newInstance("packagename");
}
#Bean public MessagingService messagingService() {
return new MessagingService();
}
}
Thanks.
Kavitha.
** Solved **
My test case now looks like this.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(classes = {AppConfig.class})`
public class ReferralExchangeEndpointTest {
#Autowired
ReferralExchangeEndpoint referralExchangeEndpoint;
#Autowired
private JAXBContext jaxbContext;
private Marshaller marshaller;
private Unmarshaller unmarshaller;
#Before
public void setUp() throws Exception {
marshaller = jaxbContext.createMarshaller();
unmarshaller = jaxbContext.createUnmarshaller();
}
#Test
public void send() throws Exception {
File payload = new File("src/test/resources/payload.xml");
JAXBElement jbe = (JAXBElement) unmarshaller.unmarshal(payload);
SendRequestMessage sendRequestMessage = (SendRequestMessage) jbe.getValue();
JAXBElement<SendResponseMessage> response = referralExchangeEndpoint.send(sendRequestMessage);
//TODO add remaining assertions on response after confirming what should the service return for these attributes.
assertEquals("SiteId wrong in response: ", "siteId", response.getValue().getSiteId());
}
}`
Related
I am trying to write Unit test to the handler function, I followed the example from the Spring project. Can someone help me why the following test is throwing UnsupportedMediaTypeStatusException?
Thanks
Handler function
public Mono<ServerResponse> handle(ServerRequest serverRequest) {
log.info("{} Processing create request", serverRequest.exchange().getLogPrefix());
return ok().body(serverRequest.bodyToMono(Person.class).map(p -> p.toBuilder().id(UUID.randomUUID().toString()).build()), Person.class);
}
Test Class
#SpringBootTest
#RunWith(SpringRunner.class)
public class MyHandlerTest {
#Autowired
private MyHandler myHandler;
private ServerResponse.Context context;
#Before
public void createContext() {
HandlerStrategies strategies = HandlerStrategies.withDefaults();
context = new ServerResponse.Context() {
#Override
public List<HttpMessageWriter<?>> messageWriters() {
return strategies.messageWriters();
}
#Override
public List<ViewResolver> viewResolvers() {
return strategies.viewResolvers();
}
};
}
#Test
public void handle() {
Gson gson = new Gson();
MockServerWebExchange exchange = MockServerWebExchange.from(
MockServerHttpRequest.post("/api/create")
.body(gson.toJson(Person.builder().firstName("Jon").lastName("Doe").build())));
MockServerHttpResponse mockResponse = exchange.getResponse();
ServerRequest serverRequest = ServerRequest.create(exchange, HandlerStrategies.withDefaults().messageReaders());
Mono<ServerResponse> serverResponseMono = myHandler.handle(serverRequest);
Mono<Void> voidMono = serverResponseMono.flatMap(response -> {
assertThat(response.statusCode()).isEqualTo(HttpStatus.OK);
boolean condition = response instanceof EntityResponse;
assertThat(condition).isTrue();
return response.writeTo(exchange, context);
});
StepVerifier.create(voidMono)
.expectComplete().verify();
StepVerifier.create(mockResponse.getBody())
.consumeNextWith(a -> System.out.println(a))
.expectComplete().verify();
assertThat(mockResponse.getHeaders().getContentType()).isEqualTo(MediaType.APPLICATION_JSON);
}
}
Error Message:
java.lang.AssertionError: expectation "expectComplete" failed (expected: onComplete(); actual: onError(org.springframework.web.server.UnsupportedMediaTypeStatusException: 415 UNSUPPORTED_MEDIA_TYPE "Content type 'application/octet-stream' not supported for bodyType=com.example.demo.Person"))
I found that I missed .contentType(MediaType.APPLICATION_JSON) to my mock request.
MockServerWebExchange.from(
MockServerHttpRequest.post("/api/create").contentType(MediaType.APPLICATION_JSON)
.body(gson.toJson(Person.builder().firstName("Jon").lastName("Doe").build())));
fixed my issue.
The controller method I am testing
#GetMapping("/customers")
#ResponseBody
public DeferredResult<ResponseEntity<Resources<Resource<Customer>>>> getAllCustomers(
#PageableDefault(page = 0, size = 20) #SortDefault.SortDefaults({
#SortDefault(sort = "name", direction = Direction.ASC) }) Pageable pageable,
PagedResourcesAssembler<Customer> assembler, HttpServletRequest request) {
DeferredResult<ResponseEntity<Resources<Resource<Customer>>>> response = new DeferredResult<>(
Long.valueOf(1000000));
response.onTimeout(() -> response
.setErrorResult(ResponseEntity.status(HttpStatus.REQUEST_TIMEOUT).body("Request timed out.")));
response.onError((Throwable t) -> {
response.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).body("An error occured."));
});
ListenableFuture<Page<Customer>> future = customerService.findAll(pageable);
future.addCallback(new ListenableFutureCallback<Page<Customer>>() {
#Override
public void onSuccess(Page<Customer> result) {
Link self = new Link(
ServletUriComponentsBuilder.fromRequestUri(request).buildAndExpand().toUri().toString(),
"self");
LOGGER.debug("Generated Self Link {} for Customer Resource Collection", self.getHref());
if (result.hasContent())
response.setResult(
ResponseEntity.ok(assembler.toResource(result, customerResourceAssembler, self)));
else
response.setErrorResult(ResponseEntity.notFound());
LOGGER.debug("Returning Response with {} customers", result.getNumber());
}
#Override
public void onFailure(Throwable ex) {
LOGGER.error("Could not retrieve customers due to error", ex);
response.setErrorResult(ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR)
.body("Could not save customers list due to server error."));
}
});
return response;
}
the unit test
#RunWith(SpringRunner.class)
#WebMvcTest(CustomerController.class)
#EnableSpringDataWebSupport
#Import({ CustomerResourceAssember.class, BranchResourceAssembler.class, InvoiceResourceAssembler.class,
CustomerAsyncService.class })
public class CustomerControllerTests {
#Autowired
private MockMvc mockMvc;
#Autowired
CustomerAsyncService customerService;
#MockBean
private CustomerRepository customerRepository;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void testWhenNoCustomersThenReturnsEmptyHALDocument() throws Exception {
// Given
BDDMockito.given(customerRepository.findAll(PageRequest.of(0, 20)))
.willReturn(new PageImpl<Customer>(Collections.emptyList()));
// When
MvcResult result = mockMvc.perform(get("/customers").accept(MediaTypes.HAL_JSON_VALUE)).andDo(print())
.andExpect(request().asyncStarted())
.andExpect(request().asyncResult(new PageImpl<Customer>(Collections.emptyList()))).andReturn();
// Then
mockMvc.perform(asyncDispatch(result)).andExpect(status().isOk());
}
This test neve completes, doesn't even time out on my IDE, I have to kill it everytime I run it, if run the entire app however this /customers endpoint gives a 404 when there are no customers added to the application.
What do I need to do make sure this test completes, the CustomerService call ultimately calls CustomerRepository which I have mocked because I couldn't get my brains around how to mock the async call to service method. the customer service class is as follows
#Async
#Service
public class CustomerAsyncService {
private CustomerRepository customerRepository;
#Autowired
public CustomerAsyncService(CustomerRepository customerRepository) {
this.customerRepository = customerRepository;
}
#Transactional(readOnly = true, isolation = Isolation.SERIALIZABLE)
public ListenableFuture<Page<Customer>> findAll(Pageable pageable) {
return AsyncResult.forValue(customerRepository.findAll(pageable));
}
I was hoping mocking the Repository method would do the trick. How do I mock the async service call
My bad was using mocks wrongly, this worked
#RunWith(SpringRunner.class)
#WebMvcTest(CustomerController.class)
#Import({ CustomerResourceAssember.class, BranchResourceAssembler.class, InvoiceResourceAssembler.class,
CustomerAsyncService.class })
public class CustomerControllerTests {
#MockBean
private CustomerRepository customerRepository;
#InjectMocks
CustomerAsyncService customerService = new CustomerAsyncService(customerRepository);
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
JacksonTester.initFields(this, objectMapper);
}
#Test
public void testReturnsNotFoundForEmptyGetAllCustomersResult() throws Exception {
// Given
Page<Customer> emptyPage = new PageImpl<Customer>(Collections.emptyList());
BDDMockito.given(customerRepository.findAll(any(Pageable.class))).willReturn(emptyPage);
// When
MvcResult result = mockMvc.perform(get("/customers")).andExpect(request().asyncStarted()).andDo(print()).andReturn();
// Then
mockMvc.perform(asyncDispatch(result)).andDo(print()).andExpect(status().isNotFound());
}
}
I am trying to write Test case for controller using JUnit and mockito. But I am getting error as JSON can not be null or empty. can any one please tell me what I m doing wrong?
DepartmentController
#RestController
#RequestMapping("/api.spacestudy.com/SpaceStudy")
public class DepartmentController {
#Autowired
DepartmentService depService;
#GetMapping("/Control/SearchFilter/loadDepartments")
public ResponseEntity<Set<Department>> findDepName() {
Set<Department> depname = depService.findDepName();
return ResponseEntity.ok(depname);
}
DepartmentControllerTest
#RunWith(SpringJUnit4ClassRunner.class)
public class DepartmentControllerTest {
private MockMvc mockMvc;
#Mock
public DepartmentService depService;
#InjectMocks
DepartmentController departmentController;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(departmentController).build();
}
#Test(timeout = 10000)
public void findDepNameTest() throws Exception
{
Department dep = new Department();
dep.setsDeptName("ABC");
Set<Department> department = new HashSet<Department>();
department.add(dep);
Mockito.when(depService.findDepName()).thenReturn(department);
mockMvc.perform(get("/api.spacestudy.com/SpaceStudy/LoadDept").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$[0].sDeptName" , is("abc")));
}
}
Failure Trace
java.lang.AssertionError: No value at JSON path "$[0].sDeptName", exception: json can not be null or empty
at org.springframework.test.util.JsonPathExpectationsHelper.evaluateJsonPath(JsonPathExpectationsHelper.java:245)
at org.springframework.test.util.JsonPathExpectationsHelper.assertValue(JsonPathExpectationsHelper.java:73)
at org.springframework.test.web.servlet.result.JsonPathResultMatchers$1.match(JsonPathResultMatchers.java:87)
at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:171)
at com.spacestudy.DepartmentControllerTest.findDepNameTest(DepartmentControllerTest.java:76)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at
I found my mistake. I am giving wrong path for get Request in above code. I changed that path and its working properly.
mockMvc.perform(get("/api.spacestudy.com/SpaceStudy/Control/SearchFilter/loadDepartmentsLoadDept").accept(MediaType.APPLICATION_JSON))
I am having issues trying to test
THe following REST method
#GetMapping
#RequestMapping("/create")
ResponseEntity<Order> createOrders(#RequestBody String body) {
ObjectMapper mapper = new ObjectMapper();
try{
Map<String,Object> mapBody = mapper.readValue(body,Map.class);
Long cusId = Long.valueOf((int)mapBody.get("customer_id"));
Customer customer = customerRepository.findOne(cusId);
Product product = productRepository.findByProductName((String)mapBody.get("product_name"));
Order order = new Order(customer,product,(int)mapBody.get("quantity"));
orderRepository.saveAndFlush(order);
return new ResponseEntity(order, HttpStatus.OK);
}
catch(Exception e){
e.printStackTrace();
return new ResponseEntity("error with original port", HttpStatus.EXPECTATION_FAILED);
}
}
I have tried numrous things so for and nothing seems to work.
Doing a call to the REST method works fine but it seems I can use either
#AutoConfigureMockMvc or #DataJpaTest in my testing
My code is currently as follows
#SpringBootTest
#AutoConfigureMockMvc
#DataJpaTest
public class OrderTest {
#Autowired
private MockMvc mockMvc;
#Autowired
private ProductRepository productRepositoryTest;
#Autowired
private CustomerRepository customerRepositoryTest;
#Test
public void submitNewOrdersForBricks() {
try {
Customer cus1 = new Customer("cus1");
customerRepositoryTest.saveAndFlush(cus1);
Product pro1 = new Product("brick1","red brick",0.96);
productRepositoryTest.saveAndFlush(pro1);
this.mockMvc.perform(post("/create")
.content("{\"customer_id\":"+cus1.getCustomerId()+",\"product_name\":\"brick1\",\"quantity\":150}")
.contentType(MediaType.APPLICATION_JSON))
.andDo(print()).andExpect(status().isCreated())
.andExpect(jsonPath("$.order_id").value(1));
}
catch(Exception e){
e.printStackTrace();
}
}
}
I have also tried using
when(customerRepository.findOne(cusId)).thenReturn(cus1);
This did not have any effect in my controller.
Please note that the controller method createOrders is only called when I remove #DataJpaTest, but then IDs are not created for customer and product.
Any help would be great.
#DataJpaTest is for repository test. In this case, #DataJpaTest is useless.
And, in test class, you missed
#Autowired
private OrderRepository orderRepository;
I have the following code I'm trying to unit test :
if (networkUtils.isOnline()) {
return remoteDataSource.postComment(postId, commentText)
.doOnSuccess(postCommentResponse ->
localDataSource.postComment(postId, commentText))
.subscribeOn(schedulerProvider.io())
.observeOn(schedulerProvider.mainThread());
} else {
return Single.error(new IOException());
}
And this is how I'm trying to test it :
#Test
public void postComment_whenIsOnline_shouldCallLocalToPostComment() throws Exception {
// Given
when(networkUtils.isOnline())
.thenReturn(true);
String postId = "100";
String comment = "comment";
Response<PostCommentResponse> response = postCommentResponse();
when(remoteDataSource.postComment(anyString(), anyString()))
.thenReturn(Single.just(response));
// When
repository.postComment(postId, comment);
// Then
verify(localDataSource).postComment(postId, comment);
}
where I fake Response from Retrofit like :
private Response<PostCommentResponse> postCommentResponse() {
PostCommentResponse response = new PostCommentResponse();
response.setError("0");
response.setComment(postCommentResponseNestedItem);
return Response.success(response);
}
but it results to : Actually, there were zero interactions with this mock.
Any ideas ?
EDIT :
#RunWith(MockitoJUnitRunner.class)
public class CommentsRepositoryTest {
#Mock
private CommentsLocalDataSource localDataSource;
#Mock
private CommentsRemoteDataSource remoteDataSource;
#Mock
private NetworkUtils networkUtils;
#Mock
private PostCommentResponseNestedItem postCommentResponseNestedItem;
private CommentsRepository repository;
#Before
public void setUp() throws Exception {
MockitoAnnotations.initMocks(this);
BaseSchedulerProvider schedulerProvider = new ImmediateSchedulerProvider();
repository = new CommentsRepository(localDataSource, remoteDataSource, networkUtils, schedulerProvider);
}
// tests
}
When you want to test an Observable you have to subscribe to it so it will start emitting items.
As soon as I used :
TestObserver<Response<PostCommentResponse>> testObserver = new TestObserver<>();
and subscribed to :
repository.postComment(postId, comment)
.subscribe(testObserver);
the test worked as expected.