I am trying to reach this Steam Market link: http://steamcommunity.com/market/priceoverview/?appid=730¤cy=3&market_hash_name=Clutch%20Case
If I do it in Postman everything is good, but when I am trying to do it using restTemplate it gives me null.
package com.example.CsgoInvestorPriceTracker.service;
import com.example.CsgoInvestorPriceTracker.dto.SteamMarketItem;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.http.*;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;
#Service
public class SteamMarketService {
#Autowired
private RestTemplate restTemplate;
public SteamMarketItem getSingleSteamMarketItem(String market_hash_name) {
SteamMarketItem steamMarketItem;
steamMarketItem =
restTemplate.exchange(
"http://steamcommunity.com/market/priceoverview/?appid=730¤cy=3&market_hash_name=Clutch%20Case",
HttpMethod.GET,
null,
new ParameterizedTypeReference<SteamMarketItem>() {
}
).getBody();
return steamMarketItem;
}
}
My SteamMarketItem class looks like this.
package com.example.CsgoInvestorPriceTracker.dto;
import lombok.*;
#Getter
#Setter
#AllArgsConstructor
#NoArgsConstructor
#Builder
public class SteamMarketItem {
private String success;
private String lowest_price;
private String volume;
private String median_price;
}
The json it should return.
{"success":true,"lowest_price":"0,34€","volume":"86,030","median_price":"0,35€"}
Has anyone faced a similar issue?
Related
I'm using spring-boot 2.7.4 and spring-cloud-dependencies 2021.0.4.
I haven't found any solution in spring documentation for add trustedTypes in BatchMessagingMessageConverter. I'm using kafka for read messages in batch-mode. If I insert a custom header (my own class) when the consumer read the header return a DefaultKafkaHeaderMapper$NonTrustedHeaderType and not my class.
I have in my configuration this key to activate batch mode:
spring.cloud.stream.bindings.nameBind-in-0.consumer.batch-mode=true
I tried in debug to add to headerMapper in BatchMessagingMessageConverter the package of my class and all works fine. There is a way to specify my package in configuration?
I followed the documentation https://docs.spring.io/spring-cloud-stream/docs/3.2.5/reference/html/spring-cloud-stream-binder-kafka.html#kafka-binder-properties, I created a bean like this:
#Bean("kafkaHeaderMapperCustom")
KafkaHeaderMapper getKafkaHeaderMapperCustom() {
var defKHM = new DefaultKafkaHeaderMapper();
defKHM.addTrustedPackages("*");
return defKHM;
}
Specified to key spring.cloud.stream.kafka.binder.headerMapperBeanName in configuration but doesn't work, I suppose that configuration is valid for not batch context?
I tried also these properties:
spring.kafka.consumer.properties.spring.json.trusted.packages
spring.json.trusted.packages
EDIT - Add example:
import org.springframework.boot.ApplicationRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.stream.function.StreamBridge;
import org.springframework.context.annotation.Bean;
import org.springframework.kafka.support.DefaultKafkaHeaderMapper;
import org.springframework.kafka.support.KafkaHeaderMapper;
import org.springframework.kafka.support.KafkaHeaders;
import org.springframework.messaging.Message;
import org.springframework.messaging.MessageHeaders;
import org.springframework.messaging.support.MessageBuilder;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
#SpringBootApplication
public class Application {
public static final String HEADER_KEY = "CUSTOM_HEADER_KEY";
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
#Bean
public ApplicationRunner runner(StreamBridge streamBridge) {
return args -> {
var headers = new MessageHeaders(Map.of(HEADER_KEY, new CustomHeaderClass("field1Value", LocalDate.now())));
headers.get(KafkaHeaders.BATCH_CONVERTED_HEADERS);
var message = MessageBuilder.createMessage(new ExampleBrokenHeaderEntity("randomValue", "randomName"), headers);
streamBridge.send("stackoverflow-example", message);
};
}
#Bean
public Consumer<Message<List<ExampleBrokenHeaderEntity>>> readFromKafkaBatchMode() {
return messages -> {
var brokenHeader = ((ArrayList<Map<String, Object>>) messages.getHeaders().get(KafkaHeaders.BATCH_CONVERTED_HEADERS)).get(0).get(HEADER_KEY);
System.out.println("BATCH - Class header: " + (brokenHeader != null ? brokenHeader.getClass() : null));
};
}
#Bean
public Consumer<Message<ExampleBrokenHeaderEntity>> readFromKafkaNoBatchMode() {
return messages -> {
var brokenHeader = messages.getHeaders().get(HEADER_KEY);
System.out.println("NO_BATCH - Class header: " + (brokenHeader != null ? brokenHeader.getClass() : null));
};
}
#Bean("kafkaHeaderMapperCustom")
public KafkaHeaderMapper getKafkaHeaderMapperBatchMode() {
var kafkaHeaderMapperCustom = new DefaultKafkaHeaderMapper();
kafkaHeaderMapperCustom.addTrustedPackages("*");
return kafkaHeaderMapperCustom;
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import java.time.LocalDate;
#Data
#NoArgsConstructor
#AllArgsConstructor
public class CustomHeaderClass {
private String field1;
private LocalDate field2;
}
import lombok.AllArgsConstructor;
import lombok.Data;
#Data
#AllArgsConstructor
public final class ExampleBrokenHeaderEntity {
private String type;
private String name;
}
spring.cloud.stream.kafka.binder.brokers=x.x.x.x:xxxx
spring.cloud.function.definition=readFromKafkaNoBatchMode;readFromKafkaBatchMode
spring.cloud.stream.bindings.readFromKafkaBatchMode-in-0.destination=stackoverflow-example
spring.cloud.stream.bindings.readFromKafkaBatchMode-in-0.group=readFromKafkaBatchMode
spring.cloud.stream.bindings.readFromKafkaBatchMode-in-0.consumer.batch-mode=true
spring.cloud.stream.bindings.readFromKafkaNoBatchMode-in-0.destination=stackoverflow-example
spring.cloud.stream.bindings.readFromKafkaNoBatchMode-in-0.group=readFromKafkaNoBatchMode
spring.cloud.stream.kafka.binder.headerMapperBeanName=kafkaHeaderMapperCustom
The output of example is:
NO_BATCH - Class header: class com.example.kafka.header.types.CustomHeaderClass
BATCH - Class header: class org.springframework.kafka.support.DefaultKafkaHeaderMapper$NonTrustedHeaderType
It's a bug; the binder only sets the custom header mapper on a record converter:
private MessageConverter getMessageConverter(
final ExtendedConsumerProperties<KafkaConsumerProperties> extendedConsumerProperties) {
MessageConverter messageConverter = BindingUtils.getConsumerMessageConverter(getApplicationContext(),
extendedConsumerProperties, this.configurationProperties);
if (messageConverter instanceof MessagingMessageConverter) {
((MessagingMessageConverter) messageConverter).setHeaderMapper(getHeaderMapper(extendedConsumerProperties));
}
return messageConverter;
}
There should be similar code for when the converter is a BatchMessagingMessageConverter.
The work around is to define a custom message converter for the batch consumer:
#Bean("batchConverter")
BatchMessageConverter batchConverter(KafkaHeaderMapper kafkaHeaderMapperCustom) {
BatchMessagingMessageConverter batchConv = new BatchMessagingMessageConverter();
batchConv.setHeaderMapper(kafkaHeaderMapperCustom);
return batchConv;
}
spring.cloud.stream.kafka.bindings.readFromKafkaBatchMode-in-0.consumer.converter-bean-name=batchConverter
NO_BATCH - Class header: class com.example.demo.So74294156Application$CustomHeaderClass
BATCH - Class header: class com.example.demo.So74294156Application$CustomHeaderClass
Please open an issue against Spring Cloud Stream, referencing this question/answer.
I have a simple MyLibraryApplication which is having code to invoke POST(TransactionControllerImpl.issueBookToMember) and PATCH(TransactionControllerImpl.returnBookTransaction) methods. I have referred some links on net and tried my best to write code to invoke PATCH method. The code can be found in TransactionControllerTest(testBookReturnUsingRestTemplate and testBookReturnUsingMockMvc methods). The code for invoking POST is working fine but the code for invoking PATCH is not working. Control never reaches returnBookTransaction inside TransactionControllerImpl.
Error: Invalid PATCH method.
I am looking for code snippet for TransactionControllerTest.testBookReturnUsingRestTemplate and testBookReturnUsingMockMvc methods. Can someone help me in getting this code into proper shape?
package com.mycompany.techtrial;
import java.util.Map;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestBody;
import com.mycompany.techtrial.Transaction;
public interface TransactionController {
public ResponseEntity<Transaction> issueBookToMember(#RequestBody Map<String, String> params);
public ResponseEntity<Transaction> returnBookTransaction(#PathVariable(name="transaction-id") Long transactionId);
}
/**
*
*/
package com.mycompany.techtrial;
import java.time.LocalDateTime;
import java.util.List;
import java.util.ListIterator;
import java.util.Map;
import java.util.Optional;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.PatchMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#RestController
public class TransactionControllerImpl implements TransactionController{
/*
* PLEASE DO NOT CHANGE SIGNATURE OR METHOD TYPE OF END POINTS
* Example Post Request : { "book":"Java8 Primer","member":"Test 1" }
*/
#PostMapping(path = "/api/transaction")
public ResponseEntity<Transaction> issueBookToMember(#RequestBody Map<String, String> params){
String book = params.get("book");
String member = params.get("member");
Transaction transaction = new Transaction();
transaction.setId(1L);
transaction.setBook(book);
transaction.setMember(member);
transaction.setDateOfIssue(LocalDateTime.now());
transaction.setDateOfReturn(Transaction.getDefaultReturnDate());
return ResponseEntity.ok().body(transaction);
}
/*
* PLEASE DO NOT CHANGE SIGNATURE OR METHOD TYPE OF END POINTS
*/
#PatchMapping(path= "/api/transaction/{transaction-id}/return")
public ResponseEntity<Transaction> returnBookTransaction(#PathVariable(name="transaction-id") Long transactionId){
String book = "Java8 Primer";
String member = "Test 1";
Transaction transaction = new Transaction();
transaction.setId(1L);
transaction.setBook(book);
transaction.setMember(member);
transaction.setDateOfIssue(LocalDateTime.now().minusDays(10));
transaction.setDateOfReturn(LocalDateTime.now());
return ResponseEntity.ok().body(transaction);
}
}
package com.mycompany.techtrial;
import java.util.HashMap;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.SpringBootTest.WebEnvironment;
import org.springframework.boot.test.web.client.TestRestTemplate;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
#RunWith(SpringJUnit4ClassRunner.class)
#SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class TransactionControllerTest {
MockMvc mockMvc;
#Mock
private TransactionController transactionController;
#Autowired
private TestRestTemplate template;
#Before
public void setup() throws Exception {
mockMvc = MockMvcBuilders.standaloneSetup(transactionController).build();
}
#Test
public void testBookIssue() throws Exception {
HttpEntity<Object> transaction = getHttpEntity(
"{\"book\": \"Java8 Primer\", \"member\": \"Test 1\" }");
ResponseEntity<Transaction> response = template.postForEntity(
"/api/transaction", transaction, Transaction.class);
Assert.assertEquals("Java8 Primer", response.getBody().getBook());
Assert.assertEquals("Test 1", response.getBody().getMember());
Assert.assertEquals(200,response.getStatusCode().value());
}
#Test
public void testBookReturnUsingRestTemplate() throws Exception {
Long transactionId = new Long(1);
HashMap<String,Long> uriVariables = new HashMap<String,Long>();
uriVariables.put("transaction-id", transactionId);
Transaction transaction = template.patchForObject(
"/api/transaction/{transaction-id}/return",null, Transaction.class, uriVariables);
Assert.assertEquals(new Long(1), transaction.getId());
//Assert.assertEquals(200,response.getStatusCode().value());
}
#Test
public void testBookReturnUsingMockMvc() throws Exception {
Long transactionId = new Long(1);
HashMap<String,Long> uriVariables = new HashMap<String,Long>();
uriVariables.put("transaction-id", transactionId);
ResultActions obj = mockMvc.perform( MockMvcRequestBuilders
.patch("/api/transaction/{transaction-id}/return",transactionId)
.content("")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON));
System.out.println(obj.getClass());
HttpStatus status = obj.andReturn().getModelAndView().getStatus();
boolean success = status.is2xxSuccessful();
System.out.println("success="+success);
Assert.assertEquals(new Long(1), transactionId);
//Assert.assertEquals(200,response.getStatusCode().value());
}
private HttpEntity<Object> getHttpEntity(Object body) {
HttpHeaders headers = new HttpHeaders();
headers.setContentType(MediaType.APPLICATION_JSON);
return new HttpEntity<Object>(body, headers);
}
}
package com.mycompany.techtrial;
import java.io.Serializable;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.LocalTime;
public class Transaction implements Serializable {
private static final long serialVersionUID = 8951221480021840448L;
private static final LocalDateTime defaultReturnDate = LocalDateTime.of(LocalDate.of(2299, 12, 31), LocalTime.of(12, 0, 0));
Long id;
private String book;
private String member;
public String getBook() {
return book;
}
public void setBook(String book) {
this.book = book;
}
public String getMember() {
return member;
}
public void setMember(String member) {
this.member = member;
}
//Date and time of issuance of this book
LocalDateTime dateOfIssue;
//Date and time of return of this book
LocalDateTime dateOfReturn;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public LocalDateTime getDateOfIssue() {
return dateOfIssue;
}
public void setDateOfIssue(LocalDateTime dateOfIssue) {
this.dateOfIssue = dateOfIssue;
}
public LocalDateTime getDateOfReturn() {
return dateOfReturn;
}
public void setDateOfReturn(LocalDateTime dateOfReturn) {
this.dateOfReturn = dateOfReturn;
}
#Override
public String toString() {
return "Transaction [id=" + id + ", book=" + book + ", member=" + member + ", dateOfIssue=" + dateOfIssue + ", dateOfReturn=" + dateOfReturn + "]";
}
//#PrePersist
void preInsert() {
if (this.dateOfReturn == null)
this.dateOfReturn = defaultReturnDate;
}
public static LocalDateTime getDefaultReturnDate() {
return defaultReturnDate;
}
}
package com.mycompany.techtrial;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
#SpringBootApplication
public class MyLibraryApplication {
public static void main(String[] args) {
SpringApplication.run(MyLibraryApplication.class, args);
}
}
It seems to be a known issue with the RestTemplate default Http client.
RestTemplate bug
A workaround for this would be to use the apache httpcomponents httpclient library in the RestTemplateBuilder.setRequestFactory and pass that in the constructor to TestRestTemplate
After that you can use the exchange method on the TestRestTemplate class and do a PATCH request.
Sample code to create TestRestTemplate:
Supplier<ClientHttpRequestFactory> supplier = () -> {
return new HttpComponentsClientHttpRequestFactory();
};
restTemplateBuilder.requestFactory(supplier);
TestRestTemplate testRestTemplate = new TestRestTemplate(restTemplateBuilder);
testRestTemplate.exchange("/api/transaction/{transaction-id}/return",HttpMethod.PATCH,null,Transaction.class,uriVariables);
I'm new to Mockito and trying to test my service layer. My DAO layer is #Autowired in service and Hibernate is also autowired. Hibernate is not loading while testing. I always get NullPointerException. Here is my code:
EmployeeService (Interface)
package com.spring.crud.service;
import java.util.List;
import com.spring.crud.entity.Employee;
public interface EmployeeService {
Employee save(Employee employee);
boolean update(Employee employee);
Employee find(Integer id);
List<Employee> getEmployees();
boolean remove(Integer id);
}
EmployeeServiceImpl (Class)
package com.spring.crud.service;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import com.spring.crud.dao.EmployeeDAO;
import com.spring.crud.entity.Employee;
#Service
public class EmployeeServiceImpl implements EmployeeService {
#Autowired
private EmployeeDAO dao;
public Employee save(Employee employee) {
return dao.save(employee);
}
public boolean update(Employee employee) {
return dao.update(employee);
}
public Employee find(Integer id) {
return dao.find(id);
}
public List<Employee> getEmployees() {
return dao.getEmployees();
}
public boolean remove(Integer id) {
return dao.remove(id);
}
}
EmployeeDAO (Interface)
package com.spring.crud.dao;
import java.util.List;
import com.spring.crud.entity.Employee;
public interface EmployeeDAO {
Employee save(Employee employee);
boolean update(Employee employee);
Employee find(Integer id);
List<Employee> getEmployees();
boolean remove(Integer id);
}
EmployeeDAOImpl (Class)
package com.spring.crud.dao;
import java.util.List;
import javax.transaction.Transactional;
import org.hibernate.Query;
import org.hibernate.Session;
import org.springframework.stereotype.Repository;
import com.spring.crud.entity.Employee;
#Transactional
#Repository
public class EmployeeDAOImpl extends HibernateUtil implements EmployeeDAO{
public Employee save(Employee employee) {
Session session = getCurrentSession();
session.save(employee);
return employee;
}
public boolean update(Employee employee) {
Session session = getCurrentSession();
session.update(employee);
return false;
}
public Employee find(Integer id) {
Session session = getCurrentSession();
Employee employee = (Employee)session.get(Employee.class, id);
return employee;
}
public List<Employee> getEmployees() {
Session session = getCurrentSession();
Query query = session.createQuery("from Employee");
#SuppressWarnings("unchecked")
List<Employee> employees = (List<Employee>)query.list();
return employees;
}
public boolean remove(Integer id) {
Session session = getCurrentSession();
Employee employee = (Employee)session.get(Employee.class, id);
if(employee!=null){
session.delete(employee);
return true;
}
return false;
}
}
HibernateUtil
package com.spring.crud.dao;
import javax.annotation.PostConstruct;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.orm.hibernate3.support.HibernateDaoSupport;
public class HibernateUtil extends HibernateDaoSupport{
#Autowired
private SessionFactory sessionFactory;
#PostConstruct
public void init() {
setSessionFactory(sessionFactory);
}
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
EmployeeServiceTest (Test class)
package com.spring.crud.test;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.junit.Assert.assertTrue;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.junit.Before;
import org.junit.Test;
import org.mockito.MockitoAnnotations;
import org.mockito.Spy;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.test.context.ContextConfiguration;
import com.spring.crud.config.WebConfig;
import com.spring.crud.dao.EmployeeDAO;
import com.spring.crud.dao.EmployeeDAOImpl;
import com.spring.crud.entity.Employee;
import com.spring.crud.service.EmployeeService;
import com.spring.crud.service.EmployeeServiceImpl;
#ContextConfiguration(classes = {WebConfig.class})
public class EmployeeServiceTest {
private EmployeeDAO employeeDAO;
private EmployeeService employeeService = new EmployeeServiceImpl();
#Spy
List<Employee> employees = new ArrayList<Employee>();
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
employeeDAO = mock(EmployeeDAOImpl.class);
}
#Test
public void listEmployees() {
}
#Test
public void create() {
Employee employee = new Employee();
employee.setDateOfBirth(new Date());
employee.setGender("male");
employee.setName("Ashutosh");
when(employeeDAO.save(any(Employee.class)))
.thenAnswer(new Answer<Employee>() {
public Employee answer(InvocationOnMock invocation) throws Throwable {
Employee employee = (Employee) invocation.getArguments()[0];
employee.setId(1);
return employee;
}
});
assertNull(employee.getId());
employee = employeeService.save(employee);
assertNotNull(employee.getId());
assertTrue(employee.getId()>0);
}
#Test
public void edit() {
}
#Test
public void update() {
}
#Test
public void remove() {
}
}
I can't find much on this on the internet.
Just because you create a mock employee DAO in your test doesn't mean that your service will use it. It won't. When you do
new EmployeeServiceImpl();
you create an instance of the service, and its DAO field is left uninitialized (so null).
Use constructor injection, and pass the mock DAO to the service constructor:
public class EmployeeServiceImpl implements EmployeeService {
private EmployeeDAO dao;
#Autowired
public EmployeeServiceImpl(EmployeeDAO dao) {
this.dao = dao;
}
...
}
And/or at least use Mockito annotations correctly:
#Mock
private EmployeeDAO employeeDAO;
#InjectMocks
private EmployeeServiceImpl employeeService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
OK, I found some fixes and now the test runs.
First, I fixed the HibernateUtil
package com.spring.crud.dao;
import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
public class HibernateUtil{
#Autowired
private SessionFactory sessionFactory;
public Session getCurrentSession() {
return sessionFactory.getCurrentSession();
}
}
This is the EmployeeServiceTest class
package com.spring.crud.test;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
import static org.mockito.Matchers.any;
import static org.mockito.Mockito.when;
import java.util.Date;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;
import org.springframework.test.context.ContextConfiguration;
import com.spring.crud.config.WebConfig;
import com.spring.crud.dao.EmployeeDAO;
import com.spring.crud.entity.Employee;
import com.spring.crud.service.EmployeeServiceImpl;
#ContextConfiguration(classes = {WebConfig.class})
public class EmployeeServiceTest {
#Mock
private EmployeeDAO employeeDAO;
#InjectMocks
private EmployeeServiceImpl employeeService;
#Before
public void setup() {
MockitoAnnotations.initMocks(this);
}
#Test
public void listEmployees() {
}
#Test
public void create() {
Employee employee = new Employee();
employee.setDateOfBirth(new Date());
employee.setGender("male");
employee.setName("Ashutosh");
when(employeeDAO.save(any(Employee.class)))
.thenAnswer(new Answer<Employee>() {
public Employee answer(InvocationOnMock invocation) throws Throwable {
Employee employee = (Employee) invocation.getArguments()[0];
employee.setId(10);
return employee;
}
});
assertNull(employee.getId());
employee = employeeService.save(employee);
System.out.println("Id = " + employee.getId());
assertNotNull(employee);
assertEquals((Integer)10, (Integer)employee.getId());
}
#Test
public void edit() {
}
#Test
public void update() {
}
#Test
public void remove() {
}
}
Guys the issue is I'm getting the error
Request method 'POST' not supported
Here is my controller :
package com.mintad.spring.controllers;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.util.List;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.ui.Model;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.RestController;
import com.mintad.common.beans.Gouvernorate;
import com.mintad.common.service.GouvernorateService;
#RestController
#RequestMapping("/data")
public class DataController {
private static final Logger LOGGER = LogManager.getLogger(DataController.class);
#Autowired
private GouvernorateService gouvernorateService;
#RequestMapping(value = "/gouvernorates", method = RequestMethod.GET, produces = { "application/json" })
public ResponseEntity<List<Gouvernorate>> getGouvernorates() throws FileNotFoundException {
return new ResponseEntity<List<Gouvernorate>>(gouvernorateService.findAll(), HttpStatus.OK);
}
#RequestMapping(value = "/addGouvernorate", method = RequestMethod.POST, produces = { "application/json" })
public #ResponseBody ResponseEntity<Gouvernorate> addGouvernorate(BindingResult result, Model model, #RequestParam(name = "name") String name,
#RequestParam(name = "delegation") String delegation, #RequestParam(name = "district") String district,
#RequestParam(name = "postalCode") String postalCode) throws IOException {
LOGGER.info("addGouvernorate called");
Gouvernorate gouvernorate = new Gouvernorate(name, delegation, district, postalCode);
gouvernorateService.addGouvernorat(gouvernorate);
return new ResponseEntity<Gouvernorate>(gouvernorate, HttpStatus.OK);
}
#RequestMapping(value = "/addTest", method = RequestMethod.POST)
public #ResponseBody String addTest(BindingResult result, Model model) {
LOGGER.info("addGouvernorate called");
Gouvernorate gouvernorate = new Gouvernorate("test", "test", "test", "test");
gouvernorateService.addGouvernorat(gouvernorate);
return "Your Professional Details Updated";
}
}
I've tried so many solutions but in vain.
I'm calling the controller method as follows using chrome Postman application :
http://localhost:8080/mintad/data/addTest (POST)
http://localhost:8080/mintad/data/addGouvernorate?name=test&delegation=test&district=test&postalCode=test (POST too)
I'll be thankful for any help !
The controller version I've added is correct but it works only if I disabled crsf in my security configuration class ass follows :
package com.mintad.spring.security;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.UserDetailsService;
#Configuration
#EnableWebSecurity
#ComponentScan
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
#Autowired
DataSource dataSource;
#Autowired
#Qualifier("customUserDetailsService")
UserDetailsService userDetailsService;
#Autowired
public void configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
// #formatter:off
http.csrf().disable().
authorizeRequests()
.antMatchers("/", "/home","/data").permitAll()
.and().formLogin().loginPage("/login")
.defaultSuccessUrl("/welcome").usernameParameter("username").passwordParameter("password")
.and().exceptionHandling().accessDeniedPage("/404");
// #formatter:off
}
}
Guys I was completely mistaken in the way I've concieved the controller.
So addTest method is replace by the following :
#RequestMapping(value = "/gouv/", method = RequestMethod.POST)
public ResponseEntity<String> addGouv(#RequestBody Gouvernorate gouv) {
log("addGouv called");
gouvernorateService.addGouvernorate(gouv);
return new ResponseEntity<String>("User created", HttpStatus.CREATED);
}
Where gouvernorateService is autwired.
I am trying to create a JUnit test case for spring mvc rest controller and service that is accessed by controller.
I am using Mockito for doing the above. I'm am able to successfully invoke the mock injected controller from the test case and also when I debug I see that the mocked userService is available in the mocked contoller, but the method within the service object is not getting invoked. While debugging I observe that it just steps over the service method call.
I do not see any kind of exception too.
I am using
Maven 3
Spring 4.1.1 Release version
Junit 4.11
Java version 1.6
I have pasted my code below:
1. Test Class
package controller;
import java.io.IOException;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
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.RequestBuilder;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.myPackage.model.User;
import com.myPackage.service.IUserService;
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = "classpath:/spring/application-config.xml")
public class UserControllerTest {
private MockMvc mockMvc;
#Mock
private IUserService userService;
#InjectMocks
private UserController controller;
#Before
public void setup(){
MockitoAnnotations.initMocks(this);
this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
}
#Test
public void testRegisterUser()throws Exception{
User user = new User();
user.setCity("City");
user.setTown("Town");
user.setFirstname("Name");
user.setLastname("LastName");
user.setPassword("abc#123");
user.setUsername("abc#gmail.com");
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
}
public static byte[] convertObjectToJsonBytes(Object object) throws IOException {
ObjectMapper mapper = new ObjectMapper();
return mapper.writeValueAsBytes(object);
}
}
2. Controller under Test
package com.myPackage.controller;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import com.myPackage.model.User;
import com.myPackage.service.IUserService;
#RestController
#RequestMapping("/service/user")
public class UserController {
private static final Logger logger = LoggerFactory.getLogger(UserController.class);
#Autowired
private IUserService userService;
public IUserService getUserService() {
return userService;
}
public void setUserService(IUserService userService) {
this.userService = userService;
}
#RequestMapping(value = "/register/", method = RequestMethod.POST,headers="Accept=application/json")
public String registerUser(#RequestBody User user) {
logger.info("register user:"+user.toString());
String userDetails = userService.registerUser(user);
logger.info("user registered:"+userDetails);
return userDetails;
}
}
3. Service to be invoked within controller in test
The service method registerUser is to be invoked from controller above. I do not see any logs getting printed on the console when we run the test case. Also when debugging I see that userSerivice instance of type like this - IUserService$$EnhancerByMockitoWithCGLIB$$c00081eb is created but when I dig deep all to see the list of methods under mockhandlers registered methods, I only see 'toString' method in the list of invocations. Not sure if this gives some indication on why this method 'registerUser' in the service class below is not getting invoked during test case.
package com.myPackage.service;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.stereotype.Service;
import com.myPackage.dao.IUserDao;
import com.myPackage.model.User;
import com.myPackage.model.UserInfo;
#Service("userService")
public class UserService implements IUserService {
private static final Logger logger = LoggerFactory.getLogger(UserService.class);
#Autowired
private IUserDao userDao;
public IUserDao getUserDao() {
return userDao;
}
public void setUserDao(IUserDao userDao) {
this.userDao = userDao;
}
#Override
public String registerUser(User user) {
// TODO Auto-generated method stub
logger.info("New User for registration:",user);
if(user!=null && user.getUsername()!=null){
User alreadyExist = userDao.getUserByLogin(user.getUsername());
if(alreadyExist!=null){
return "userAlreadyExists";
}
}
logger.info("New User for registration complete:",user.getUser_id());
return null;
}
}
4. Interface implemented by UserService class in point 3 above
IUserService. The mocked userService in test class above is of type IUserService.
package com.myPackage.service;
import com.myPackage.model.User;
import com.myPackage.model.UserInfo;
public interface IUserService {
public String registerUser(User user);
}
Your method (read code) within userService will never actually be invoked from your controller because, it has been mocked out by mockito.
You have defined this yourself by doing:
#Mock
private IUserService userService;
#InjectMocks
private UserController controller;
MockitoAnnotations.initMocks(this);
If you want to assert that the method has been called you can using,
verify(userService, times(1)).registerUser(any(User.class));
#Jonas: Thanks for your insight. If i don't mock userService then at the time of unit test, userService is found null under userController method matching registerUser. And so after reading somewhere i mocked userService. Also after doing the changes as suggested by you, the mocked service method still does not get invoked - Below are my changes -
RequestBuilder builder = MockMvcRequestBuilders.post("/service/user/register/")
.contentType(MediaType.APPLICATION_JSON).content(convertObjectToJsonBytes(user));
mockMvc.perform(builder).andExpect(MockMvcResultMatchers.status().isOk());
Mockito.verify(userService, Mockito.times(1)).registerUser(Mockito.any(User.class));
If you want to test the actual service method, then autowire it:
#Autowired
private IUserService userService;
If you want to use a mock like you're doing now, you need to stub the method:
when(userService.registerUser(any(User.class))).thenReturn("expected string");