Entity class
#Getter
#NoArgsConstructor
#Entity
public class Posts {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private Long id;
#Column(length = 500, nullable = false)
private String title;
#Column(columnDefinition = "TEXT", nullable = false)
private String content;
private String author;
#Builder
public Posts(String title, String content, String author) {
this.title = title;
this.content = content;
this.author = author;
}
}
Test code
#RunWith(SpringRunner.class)
#SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class PostsAPIControllerTest {
#LocalServerPort
private int port;
#Autowired
private TestRestTemplate restTemplate;
#Autowired
private PostsRepository postsRepository; // PostsRepository extends JpaRepository<Posts, Long>
#After
public void tearDown() throws Exception {
postsRepository.deleteAll();
}
#Test
public void posts_save() throws Exception {
String title = "title";
String content = "content";
PostsSaveRequestDTO requestDTO = PostsSaveRequestDTO.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDTO, Long.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isGreaterThan(0L);
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);
assertThat(all.get(0).getContent()).isEqualTo(content);
}
}
Controller
#RequiredArgsConstructor
#RestController
public class PostsAPIController {
private final PostsService postsService;
#PostMapping("/api/v1/posts")
public Long save(#RequestBody PostsSaveRequestDTO requestDTO) {
return postsService.save(requestDTO);
}
#PutMapping("/api/v1/posts/{id}")
public Long update(#PathVariable Long id, #RequestBody PostsUpdateRequestDTO requestDTO) {
return postsService.update(id, requestDTO);
}
#GetMapping("/api/v1/posts/{id}")
public PostsResponseDTO findById(#PathVariable Long id) {
return postsService.findById(id);
}
}
I made a sample Spring Boot test code that updates DB, but test fails with following error message if I execute the code. I already defined spring.security.user.name and spring.security.user.password to application.properties file.
What is the problem? I tried to reload after removing testImplementation 'org.springframework.security:spring-security-test' from build.gradle, but nothing has changed.
Expecting:
<401 UNAUTHORIZED>
to be equal to:
<200 OK>
but was not.
There are multiple ways to mock the security using #WithMockUser, #WithAnonymousUser, #WithUserDetails, #WithSecurityContext. You can use these annotations with #Test method
You may change the roles as required in the project. You may like to explore more details here
#Test
#WithMockUser(username="admin",roles="ADMIN")
public void posts_save() throws Exception {
String title = "title";
String content = "content";
PostsSaveRequestDTO requestDTO = PostsSaveRequestDTO.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
ResponseEntity<Long> responseEntity = restTemplate.postForEntity(url, requestDTO, Long.class);
assertThat(responseEntity.getStatusCode()).isEqualTo(HttpStatus.OK);
assertThat(responseEntity.getBody()).isGreaterThan(0L);
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);
assertThat(all.get(0).getContent()).isEqualTo(content);
Related
I am trying to test the controller for creating a new league method, but it just returns null, and when I put a system.out.println in the service impl method, it doesn't print anything.
I have tried this with both LeagueService and LeagueServiceImpl, but neither works. It seems to me as if the league service is not being called.
LeagueControllerTest:
#AutoConfigureMockMvc
#WebMvcTest(controllers = LeaguesController.class)
public class LeagueControllerTests {
#Autowired
MockMvc mockMvc;
#Autowired
private ObjectMapper objectMapper;
#MockBean
LeagueServiceImpl leagueService;
#Test
public void addLeague() throws Exception {
LeagueDTO leagueDTO = new LeagueDTO("The magnificent 7", LeagueType.BRONZE.leagueType(),7);
String json = objectMapper.writeValueAsString(leagueDTO);
System.out.println(leagueService.addLeagueFromJSON(leagueDTO));
when(leagueService.addLeagueFromJSON(leagueDTO)).thenReturn("Success.");
MvcResult mvcRes = mockMvc.perform(post("/leagues/add")
.contentType(MediaType.APPLICATION_JSON)
.accept(MediaType.APPLICATION_JSON)
.content(json))
.andExpect(status().isOk())
.andReturn();
assertEquals("{\"response\":\"Success\"}", mvcRes.getResponse().getContentAsString());
}
LeagueController:
#RestController
#RequestMapping("/leagues")
public class LeaguesController {
private final LeagueService leagueService;
public LeaguesController(LeagueService leagueService) {
this.leagueService = leagueService;
}
#PostMapping(value = "/add", consumes = "application/json", produces = "application/json")
ResponseEntity<?> addLeague(#RequestBody final LeagueDTO leagueDTO) {
String response = leagueService.addLeagueFromJSON(leagueDTO);
System.out.println("MSG IN CONTROLLER: " + response);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
LeagueDTO:
#AllArgsConstructor
#NoArgsConstructor
#Getter
#Setter
public class LeagueDTO {
private String leagueName;
private String leagueType;
private Integer playerLimit;
}
League:
#Entity
#Setter
#Getter
#AllArgsConstructor
#NoArgsConstructor
#Table(name = "leagues")
public class League {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name = "leagueid", unique = true)
private Long leagueID;
#Column(name = "leaguename")
private String leagueName;
#Column(name = "leaguetype")
private String leagueType;
#Column(name = "playerlimit")
private Integer playerLimit;
#Column(name = "gamesToPlay")
private Integer gamesToPlay;
#Column(name = "playedGames")
private Integer playedGames;
#Column(name = "firstplaceuserid")
private Long firstPlaceUserID;
}
LeagueServiceImpl:
#Override
public String addLeagueFromJSON(LeagueDTO leagueDTO) {
Integer playerLimit = leagueDTO.getPlayerLimit();
String leagueName = leagueDTO.getLeagueName();
if (leagueName != null && playerLimit != null && playerLimit > 4) {
League league = new League(leagueName, leagueDTO.getLeagueType(), playerLimit);
leagueRepository.save(league);
return "Successfully created league.";
}
return "Failed to create league.";
}
League Service:
public interface LeagueService {
String addLeagueFromJSON(LeagueDTO leagueDTO);
}
Output from test:
null
MSG IN CONTROLLER: null
expected: <{"response":"Success"}> but was: <>
Expected :{"response":"Success"}
Actual :
This works in Postman and says "Success" or "Failure" and I can see the changes in DB.
I have written 1 unit Test for 1 single public method and need help from other methods of customer controller which I can refer to and write for other controllers and services.
CustomerController
#CrossOrigin(origins = "http://localhost:4200")
#RestController
#RequestMapping("/api/v1/")
public class CustomerController {
private static final Logger log = LoggerFactory.getLogger(CustomerController.class);
#Autowired
private CustomerRepository customerRepository;
public List<Customer> getAllcustomers(){
return customerRepository.findAll();
}
**public Customer createcustomer(#RequestBody Customer customer) {
log.info("inside customer add ***********");
return customerRepository.save(customer);
}**
**public ResponseEntity<Customer> getcustomerById(#PathVariable Long id) {
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("customer not exist with id :" + id));
return ResponseEntity.ok(customer);
}**
**public ResponseEntity<Customer> updatecustomer(#PathVariable Long id, #RequestBody Customer customerDetails){
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("customer not exist with id :" + id));
customer.setFullName(customerDetails.getFullName());
customer.setPhoneNumber(customerDetails.getPhoneNumber());
customer.setPhone2(customerDetails.getPhone2());
customer.setDistrict(customerDetails.getDistrict());
Customer updatedcustomer = customerRepository.save(customer);
return ResponseEntity.ok(updatedcustomer);
}**
**public ResponseEntity<Map<String, Boolean>> deletecustomer(#PathVariable Long id){
Customer customer = customerRepository.findById(id)
.orElseThrow(() -> new ResourceNotFoundException("customer not exist with id :" + id));
customerRepository.delete(customer);
Map<String, Boolean> response = new HashMap<>();
response.put("deleted", Boolean.TRUE);
return ResponseEntity.ok(response);
}**
}
Below is the Customer Model - which I am using
public class Customer {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
private String fullName;
private int phoneNumber;
private int phone2;
private String email;
private String district;
public long getId() {
return id;
}
public void setId(long id) {
this.id = id;
}
public String getFullName() {
return fullName;
}
public void setFullName(String fullName) {
this.fullName = fullName;
}
public int getPhoneNumber() {
return phoneNumber;
}
public void setPhoneNumber(int phoneNumber) {
this.phoneNumber = phoneNumber;
}
}
UnitTest for Customer.
#ExtendWith(MockitoExtension.class)
public class CustomerControllerTest {
#Mock
CustomerRepository customerRepository;
#InjectMocks
CustomerController customerController;
#Test
public void testGetAllcustomers() {
when(customerRepository.findAll()).thenReturn(getCusts());
List<Customer> res = customerController.getAllcustomers();
assertEquals(res.size(),1);
}
public List<Customer> getCusts(){
List<Customer> custs = new ArrayList<>();
Customer c = new Customer();
c.setFullName("Dinga");
custs.add(c);
return custs;
}
}
Like the above Unit Test cases, I need other methods also. Marked in Bold for which I need Unit Test cases.
For testing a rest controller, it's recommended to use mockMvc. This acts like a rest client, but it does not actually start the server. Instead it uses the spring classes to call your code in almost the same way as if it were processing a real HTTP request. MoockMvc will perform the conversion of your data to Json and retrieve a Json result. Here's the official documentation, with some examples on how to use it: springdoc. Using ObjectMapper (or JacksonTester, which uses an ObjectMapper) you can deserialize the respone into objects.
#WebMvcTest(CustomerController.class)
#ComponentScan("com.your.base.package")
class ControllerTest{
#MockBean
private CustomerRepository customerRepository;
#Autowired
private MockMvc mockMvc;
#Test
void test1(){
when(customerRepository.findAll()).thenReturn(<whatever you want>)
// call mockMvc
this.mockMvc.perform(get("/")).andDo(print())
.andExpect(status().isOk());
}
}
I have 2 entitied (Post and FileUploads), the Post entity is responsible for a user to create an advert/post and the FileUploads entity is responsible for handling image uploads together with a post. (A post can have multiple FileUploads/Images associated with it).
The issue is that I get an error:
Column 'post_id' cannot be null
I'm unsure as to what's causing it, The PK in the FileUpload entity is a String and the Post entity PK is a Long, I don't know if that could be the cause?
I am auto-generating my Post PK as well.
FileUpload.java (Entity)
#Entity
#Table(name="file_upload")
public class FileUpload {
#Id
#GenericGenerator(name = "uuid", strategy = "uuid2")
#GeneratedValue(generator = "uuid")
#Column(name="id")
private String fileId;
private int imageCount;
private String name;
private String type;
private String fileUploader;
#Lob
private byte[] data;
#ManyToOne(fetch = FetchType.LAZY)
#JoinColumn(name="post_id", nullable = false)
private Post post;
public FileUpload() {
}
public FileUpload(int imageCount, String name, String type, String fileUploader, byte[] data, Post post) {
this.imageCount = imageCount;
this.name = name;
this.type = type;
this.fileUploader = fileUploader;
this.data = data;
this.post = post;
}
Post.java (Entity)
Left out the other fields since i have a quite a bit
#Entity
public class Post {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
#NotBlank(message = "Required")
#Size(max=45, message = "Maximum of 45 letters")
#Column(unique = true)
private String title;
private String postCreatorEmail;
private String postCreator;
#OneToMany(cascade = CascadeType.ALL, fetch = FetchType.EAGER, mappedBy = "post")
private List<FileUpload> fileUploads = new ArrayList<>();
public Post() {
}
FileServiceImpl.java
Method to store images
#Service
public class FileUploadServiceImpl implements FileUploadService{
#Autowired
private FileUploadRepository fileUploadRepository;
#Autowired
private PostRepository postRepository;
private int imageCount;
#Override
public FileUpload uploadPostImage(MultipartFile file, String emailAddress) throws IOException {
Post thePost = postRepository.findPostByPostCreatorEmail(emailAddress);
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
FileUpload fileDB = new FileUpload(++imageCount, fileName, file.getContentType(), emailAddress, file.getBytes(), thePost);
return fileUploadRepository.save(fileDB);
}
}
PostServiceImpl.java
#Service
public class PostServiceImpl implements PostService{
#Autowired
private PostRepository postRepository;
#Autowired
private UserRepository userRepository;
#Autowired
private FileUploadServiceImpl fileUploadService;
private int count;
#Override
public Post createOrUpdatePost(String post, String emailAddress){
// Removed update code
Post thePost = new Post();
try {
User user = userRepository.findUserByEmailAddress(emailAddress);
ObjectMapper objectMapper = new ObjectMapper();
thePost = objectMapper.readValue(post, Post.class);
user.setTotalAds(++count);
thePost.setPostCreator(user.getFullName());
thePost.setPostCreatorEmail(emailAddress);
thePost.setFileUploads(thePost.getFileUploads());
thePost.setUser(user);
userRepository.save(user);
return postRepository.save(thePost);
// The ad with the same title already exists - go to catch block
} catch (Exception e) {
throw new PostAlreadyExistsException("Post with title " + thePost.getTitle() + " already exists");
}
}
}
PostController.java (Only adding the handler method)
#PostMapping("/create")
public ResponseEntity<?> createPost(#RequestPart("file") MultipartFile file, #Valid #RequestPart String post, BindingResult result, Principal principal) {
ResponseEntity<?> errorMap = errorValidationService.validationService(result);
if(errorMap != null) return errorMap;
String message = "";
try {
fileUploadService.uploadPostImage(file, principal.getName());
postService.createOrUpdatePost(post, principal.getName());
message = "Uploaded the file successfully: " + file.getOriginalFilename();
return ResponseEntity.status(HttpStatus.OK).body(new ApiResponse(message, true));
} catch (Exception e) {
message = "Could not upload the file: " + file.getOriginalFilename() + "!";
return ResponseEntity.status(HttpStatus.BAD_REQUEST).body(new ApiResponse(message, false));
}
}
Postman results
Console output
Post DDL MySQL
FileUpload DDL MySQL
Try to add modify your uploadPostImage to this code:
#Override
public FileUpload uploadPostImage(MultipartFile file, String emailAddress) throws IOException {
Post thePost = postRepository.findPostByPostCreatorEmail(emailAddress);
// new part:
if (thePost == null) {
throw new RuntimeException("No post found yet for eMail-Address '" + emailAddress + "' to store images for!");
}
String fileName = StringUtils.cleanPath(file.getOriginalFilename());
FileUpload fileDB = new FileUpload(++imageCount, fileName, file.getContentType(), emailAddress, file.getBytes(), thePost);
return fileUploadRepository.save(fileDB);
}
I'm working on a Spring Boot + Maven + Restful + Hibernate project! After creating the RestController for adding new Devices in database i'm getting this error:
2018-03-28 10:15:18.786 WARN 9286 --- [nio-9090-exec-9] .w.s.m.s.DefaultHandlerExceptionResolver : Failed to read HTTP message: org.springframework.http.converter.HttpMessageNotReadableException: JSON parse error: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}'); nested exception is com.fasterxml.jackson.databind.exc.MismatchedInputException: Cannot construct instance of `com.hhm.hsy.hibernate.models.Protocol` (although at least one Creator exists): no String-argument constructor/factory method to deserialize from String value ('{"id":5,"protocolName":"ProtocolForTesting","port":5202}')
at [Source: (PushbackInputStream); line: 1, column: 52] (through reference chain: com.hhm.hsy.hibernate.models.Device["protocol"])
Here is my first entity:
#Entity
#Table(name = "devices", catalog = "hqm")
public class Device implements Serializable {
private static final long serialVersionUID = -8311225474375837513L;
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "device_id", unique = true, nullable = false)
private Integer id;
#Column(name = "device_name", unique = true, nullable = false)
private String deviceName;
#ManyToOne
#JoinColumn(name = "protocol_id")
private Protocol protocol;
public Device() {
}
public Device(Integer id, String deviceName, Protocol protocol) {
this.id = id;
this.deviceName = deviceName;
this.protocol = protocol;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getDeviceName() {
return deviceName;
}
public void setDeviceName(String deviceName) {
this.deviceName = deviceName;
}
public Protocol getProtocol() {
return protocol;
}
public void setProtocol(Protocol protocol) {
this.protocol = protocol;
}
And the second entity:
#Entity
#Table(name = "protocols", catalog = "hqm")
public class Protocol implements Serializable {
#Id
#GeneratedValue(strategy = IDENTITY)
#Column(name = "protocol_id", unique = true, nullable = false)
private Integer id;
#Column(name = "protocol_name", unique = true, nullable = false, length = 45)
private String protocolName;
#Column(name = "port", nullable = false)
private Integer port;
#OneToMany(mappedBy = "protocol", cascade = CascadeType.ALL, orphanRemoval = true)
private Set<Device> devices = new HashSet<>();
public Protocol() {
}
public Protocol(Integer id, String protocolName, Integer port) {
this.id = id;
this.protocolName = protocolName;
this.port = port;
}
public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getProtocolName() {
return protocolName;
}
public void setProtocolName(String protocolName) {
this.protocolName = protocolName;
}
public Integer getPort() {
return port;
}
public void setPort(Integer port) {
this.port = port;
}
#JsonIgnore
public Set<Device> getDevices() {
return devices;
}
#JsonIgnore
public void setDevices(Set<Device> devices) {
this.devices = devices;
}
}
Controller:
#RestController
#RequestMapping(value = "/api/devices")
#ComponentScan({"com.hhm.hsy.pmcs.*"})
public class DevicesController {
#Autowired
#Qualifier(value = "deviceService")
GenericServiceIntf deviceService;
// get ALL DEVICE
#RequestMapping(value = "", method = RequestMethod.GET)
public Map<String, Object> getDevices() {
Map<String, Object> devicesMap = new HashMap<>();
devicesMap.put("devices", deviceService.getAll());
return devicesMap;
}
//save a new DEVICE
#RequestMapping(value = "", method = RequestMethod.POST, consumes = {"application/json"}, produces = {"application/json"})
#ResponseStatus(HttpStatus.CREATED)
public ResponseEntity<Device> addDevice(#RequestBody Device device) {
deviceService.save(device);
return ResponseEntity.accepted().body(device);
}
}
Service:
#Service("deviceService")
public class DeviceServiceImpl extends GenericServiceAbstractImpl<Device, Integer> implements Serializable{
private static final long serialVersionUID = 697655212967127150L;
#Autowired
public DeviceServiceImpl(#Qualifier("deviceDao") GenericDaoIntf genericDao) {
super(genericDao);
}
}
So when i'm trying to add a new device, i get the error i mentioned upper.I don't know what is causing this exception. When I try to add with post a new Protocol it's working, table is being created in the database correctly and I am getting the data correctly in GET request as well..Please help me, I'm new to springboot and restful... if some more information is required, please just inform me and i will post it! Thank you!
I tried to reproduce your problem: here, but everything works as expected.
I think it can be related with this bug.
You should try to reproduce bug with different jackson version.
EDIT:
One more thing: It looks like you try to construct Protocol instead of Device. Show us your deviceService, if you can.
Failed to read HTTP message:
org.springframework.http.converter.HttpMessageNotReadableException:
JSON parse error: Cannot construct instance of
`com.hhm.hsy.hibernate.models.Protocol
I'm attempting to use this dropwizard example and build off of it. I tried to add a column userName to the people table in Person.java like below
public class Person {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
#Column(name = "fullName", nullable = false)
private String fullName;
#Column(name = "jobTitle", nullable = false)
private String jobTitle;
#Column(name = "userName", nullable = false)
private String userName;
public Person() {
}
public Person(String fullName, String jobTitle, String userName) {
this.fullName = fullName;
this.jobTitle = jobTitle;
this.userName = userName;
}
I added the appropriate getters and setters, and equals method.
However I'm getting an error reading entity from input stream in this block.
#Test
public void testPostPerson() throws Exception {
final Person person = new Person("Dr. IntegrationTest", "Chief Wizard", "Dr. Wizard");
final Person newPerson = RULE.client().target("http://localhost:" + RULE.getLocalPort() + "/people")
.request()
.post(Entity.entity(person, MediaType.APPLICATION_JSON_TYPE))
--> .readEntity(Person.class);
assertThat(newPerson.getId()).isNotNull();
assertThat(newPerson.getFullName()).isEqualTo(person.getFullName());
assertThat(newPerson.getJobTitle()).isEqualTo(person.getJobTitle());
assertThat(newPerson.getUserName()).isEqualTo(person.getUserName());
}
the input stream error is caused by the following
Caused by: com.fasterxml.jackson.databind.exc.UnrecognizedPropertyException:
Unrecognized field "code" (class com.example.helloworld.core.Person), not marked as ignorable (4 known properties: "fullName", "id", "userName", "jobTitle"])
will #JsonIgnoreProperties annotation at the class level solve this problem? Is this safe practice?
EDIT: PersonResource.java
#Path("/people/{personId}")
#Produces(MediaType.APPLICATION_JSON)
public class PersonResource {
private final PersonDAO peopleDAO;
public PersonResource(PersonDAO peopleDAO) {
this.peopleDAO = peopleDAO;
}
#GET
#UnitOfWork
public Person getPerson(#PathParam("personId") LongParam personId) {
return findSafely(personId.get());
}
#GET
#Path("/view_freemarker")
#UnitOfWork
#Produces(MediaType.TEXT_HTML)
public PersonView getPersonViewFreemarker(#PathParam("personId") LongParam personId) {
return new PersonView(PersonView.Template.FREEMARKER, findSafely(personId.get()));
}
#GET
#Path("/view_mustache")
#UnitOfWork
#Produces(MediaType.TEXT_HTML)
public PersonView getPersonViewMustache(#PathParam("personId") LongParam personId) {
return new PersonView(PersonView.Template.MUSTACHE, findSafely(personId.get()));
}
private Person findSafely(long personId) {
return peopleDAO.findById(personId).orElseThrow(() -> new NotFoundException("No such user."));
}
I think it's because the resource fails and throws a web application exception and code is actually the http status code.
Try it like this:
Response response = RULE.client().target("http://localhost:" + RULE.getLocalPort() + "/people")
.request()
.post(Entity.entity(person, MediaType.APPLICATION_JSON_TYPE));
assertEquals(200, response.getStatus());
Person newPerson = response.readEntity(Person.class);
....
You may also debug like this:
String responseString = response.readEntity(String.class);
Which will dump you the body of the response.