unit Test cases for spring boot application - java

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());
}
}

Related

Spring Boot Application- Ambiguous mapping Cannot map method

i am creating a simple spring boot project when i run the project ran into the problem with Spring Boot Ambiguous mapping. Cannot map method. i have create two various controller those are student and course controller.i completly attached the error below.
i attached the full
**gub link here** https://github.com/raguram1986/SpringSecuritys
Full Error i attached below
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'requestMappingHandlerMapping' defined in class path resource [org/springframework/boot/autoconfigure/web/servlet/WebMvcAutoConfiguration$EnableWebMvcConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalStateException: Ambiguous mapping. Cannot map 'studentController' method
com.example.studentmanagement.Controller.StudentController#saveStudent(Student)
to {POST [/save]}: There is already 'courseController' bean method
com.example.studentmanagement.Controller.CourseController#saveCourse(Course) mapped.
Controller
#Controller
public class StudentController {
#Autowired
private StudentService service;
#GetMapping("/Student")
public String viewHomePage(Model model) {
List<Student> liststudent = service.listAll();
// model.addAttribute("liststudent", liststudent);
System.out.print("Get / ");
return "Student";
}
#GetMapping("/addStudent")
public String add(Model model) {
List<Student> liststudent = service.listAll();
model.addAttribute("liststudent", liststudent);
model.addAttribute("student", new Student());
return "addstudent";
}
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveStudent(#ModelAttribute("student") Student std) {
service.save(std);
return "Student";
}
#RequestMapping("/edit/{id}")
public ModelAndView showEditStudentPage(#PathVariable(name = "id") int id) {
ModelAndView mav = new ModelAndView("addstudent");
Student std = service.get(id);
mav.addObject("student", std);
return mav;
}
#RequestMapping("/delete/{id}")
public String deleteStudentPage(#PathVariable(name = "id") int id) {
service.delete(id);
return "Student";
}
Student
#Entity
public class Student {
#Id
#GeneratedValue(strategy= GenerationType.IDENTITY)
private Long id;
private String stname;
private String course;
private int fee;
public Student() {
}
public Student(Long id, String stname, String course, int fee) {
this.id = id;
this.stname = stname;
this.course = course;
this.fee = fee;
}
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
public String getStname() {
return stname;
}
public void setStname(String stname) {
this.stname = stname;
}
public String getCourse() {
return course;
}
public void setCourse(String course) {
this.course = course;
}
public int getFee() {
return fee;
}
public void setFee(int fee) {
this.fee = fee;
}
StudentRepository
#Repository
public interface StudentRepository extends JpaRepository<Student, Long>{
}
Service
#Service
public class StudentService
{
#Autowired
private StudentRepository repo;
public List<Student> listAll() {
return repo.findAll();
}
public void save(Student std) {
repo.save(std);
}
public Student get(long id) {
return repo.findById(id).get();
}
public void delete(long id) {
repo.deleteById(id);
}
}
In your StudentController you have the endpoint /save
#RequestMapping(value = "/save", method = RequestMethod.POST)
public String saveStudent(#ModelAttribute("student") Student std) {
service.save(std);
return "Student";
}
But you haven't included the CourseController class in your question, which is mentioned in the error.
If you have defined an endpoint /save in that CourseController, then you have to rename it. Otherwise, when you invoke /save which controller needs to be invoked cannot be determined.
Add #RequestMapping above StudentController as below
#Controller
#RequestMapping("/students")
public class StudentController {
...
}
You are getting exception because there is already a mapping defined for path
/save
without being any controller mapping, so the first with root mapping is considered, but the next time it encounters same mapping it is already registered hence it is complaining. For clarity i'd suggest to add #RequestMapping to CourseController as well.
So now your course controller also becomes:
#Controller
#RequestMapping("/courses")
public class CourseController {
...
}
The best practice is to always add a request mapping at class level as well, like in your case, add a mapping like "/students" for SutdentController and "/course" for CourseController itself and then all other methods will be under that i.e. "/student/save" and then you will not face this issue anymore.

HTTP 401 Unauthorized error occurs in Spring Boot test

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);

How to write Junit test cases for spring boot application?

I have to write some junit test cases to check entity. I'm using postgres as my database.
My entity class
#Entity
#Table(name = "display")
public class Display {
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String title;
private String group;
public Display() {
}
public Display(Long id, String title, String grp) {
this.id = id;
this.title= title;
this.group= grp;
}
public void setId(Long id) {
this.id = id;
}
public Long getId() {
return this.id;
}
public void setGroup(String id) {
this.group = id;
}
public String getGroup() {
return this.group;
}
public void settitle(String title) {
this.title = title;
}
public String gettitle() {
return this.title;
}
}
My repository
#Repository
public interface DisplayRepository extends CrudRepository<Display, Long> {
}
Interface
public interface IDisplayService {
List<Display> findAll();
}
Service class
#Service
public class DisplayService implements IDisplayService {
#Autowired
private DisplayRepository repository;
#Override
public List<Display> findAll() {
List<Display> d = (List<Display>) repository.findAll();
return d;
}
}
I tried writing junit test cases but I get Could'nt load Application. Whats the right way to write junit test cases for this?
This is the test case I wrote for service
folder : test/java/example/demo/Test.java
#RunWith(MockitoJUnitRunner.class)
#TestPropertySource("classpath:conn.properties")
public class DisplayServiceTest {
#Value("${id}")
private String value;
#Mock
private DisplayRepository DisplayReps;
#InjectMocks
private DisplayService DisplayService;
#Test
public void whenFindAll_thenReturnProductList() {
Menu m = new Menu()
m.setId(value);
List<Display> expectedDisplay = Arrays.asList(m);
doReturn(expectedDisplay).when(DisplayReps).findAll();
List<Display> actualDisplay = DisplayService.findAll();
assertThat(actualDisplay).isEqualTo(expectedDisplay);
}
in test/java/example/demo/resources
conn.properties
id=2
Its returning 0 for value
Whats the issue?
Thanks
I have managed to make your code to work. I will post only the changed classes:
The interface:
public interface DisplayRepository extends CrudRepository<Display, Long> {
Optional<Display> findByTitle(String name);
}
The test class:
#RunWith(SpringRunner.class)
#AutoConfigureTestDatabase(replace= AutoConfigureTestDatabase.Replace.NONE)
#DataJpaTest
public class DisplayRepositoryTest {
#Autowired
private TestEntityManager testEntityManager;
#Autowired
private DisplayRepository productRespository;
#Before()
public void setUp(){
Display m = new Display();
// m.setId(2L); // The ID is autogenerated; can retrieve it from the persistAndFlush result
m.setCategory("Group1");
m.setTitle("Product2");
testEntityManager.persistAndFlush(m);
}
#Test
public void whenFindByName_thenReturnProduct() {
// when
Display product = productRespository.findByTitle("Product2").orElseThrow(() -> new RuntimeException("Product not found"));
// then
assertThat(product.getTitle()).isEqualTo("Product2");
}
#Test
public void whenFindAll_thenReturnProductList() {
// when
List<Display> products = (List<Display>) productRespository.findAll();
// then
assertThat(products).hasSize(1);
}
}
When trying to run the code you provided, there were a few issues:
you were using the reserved word group as a field in the Display class. Because of this, Hibernate couldn't create the table, so I renamed it to category.
there was a compilation issue because the method findByName wasn't defined in the repository; also, there was no field name in the Display class to which the mapping to be made; because of this, I've added the method findByTitle because it's an existing field and it seemed to match the value you queried in the test method.
because the ID field is autogenerated, the test setup() failed when persisting the Display.
If you want to use #Mock for mocking classes, you must call:
#Before
public void setUp() {
MockitoAnnotations.initMocks(this);
}
You can then mock responses as usual: Mockito.when(DisplayReps.findByTitle("A")).thenReturn(Optional.of(new Display(2L, "ALFA", "GRP1")));

Clarify the sequence of events in a Spring MVC ORM web app project

My professor gave a sample Spring MVC ORM project with Hibernate but I can not figure out the sequence of events involved, in particular about the usage of service business object.
This is just a little part of the project, just to make my ideas clearer.
domain:
#Entity
#Table(name = "department")
public class Department implements Serializable {
private static final long serialVersionUID = 1L;
#Id
#GeneratedValue
private Long uid;
private String name;
#OneToMany(mappedBy="department",cascade=CascadeType.PERSIST)
private List<Employee> employees = new ArrayList<Employee>();
public Department() {
}
public Department(String name) {
this.name = name;
}
// getters, setters, hashcode() and equals(), toString()...
controller:
#Controller
#RequestMapping("/department")
public class DepartmentController {
#Autowired
#Qualifier("departmentBO")
private DepartmentBO departmentBO;
static final Logger logger = Logger.getLogger(DepartmentController.class);
#RequestMapping(value = "/home", method = RequestMethod.GET)
public String departmentHome(Model model) {
logger.debug("department home() invoked");
List<Department> list = departmentBO.findAllDepartments();
model.addAttribute("list", list);
return "departments";
}
// i'll paste just the first controller ;)
business:
public interface DepartmentBO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department department);
public void update(Department department);
}
business/impl:
#Service
#Transactional
public class DepartmentBoImpl implements DepartmentBO {
#Autowired
private DepartmentDAO departmentDao;
static final Logger logger = Logger.getLogger(DepartmentBoImpl.class);
#Override
public void save(Department department) {
departmentDao.save(department);
}
#Override
public void update(Department department) {
departmentDao.update(department);
}
#Override
public void delete(long uid) {
departmentDao.delete(uid);
}
#Override
public List<Department> findAllDepartments() {
return departmentDao.findAllDepartments();
}
#Override
public Department findByUid(Long uid) throws DataAccessException {
return departmentDao.findByUid(uid);
}
}
dao:
public interface DepartmentDAO {
public void delete(long uid);
public List<Department> findAllDepartments();
public Department findByUid(Long uid);
public void save(Department user);
public void update(Department user);
}
dao/impl:
#Repository
public class DepartmentDAOImplSf implements DepartmentDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void delete(long uid) {
Department department = (Department) sessionFactory.getCurrentSession()
.get(Department.class, uid);
sessionFactory.getCurrentSession().delete(department);
}
#Override
public void save(Department department) {
sessionFactory.getCurrentSession().save(department);
}
#Override
public void update(Department department) {
sessionFactory.getCurrentSession().saveOrUpdate(department);
}
#Override
public List<Department> findAllDepartments() {
List<Department> list = (List<Department>) sessionFactory
.getCurrentSession()
.createQuery("FROM Department").list();
return list;
}
#Override
public Department findByUid(Long uid) {
Department department = (Department) sessionFactory
.getCurrentSession().get(Department.class, uid);
return department;
}
}
I know that the order is: domain model -> controller-> service -> dao ->db, but why use a DepartmentBO? and why DepartmentBoImpl autowired DepartmentDao? Who of them act first? Something that i'm not understanding is messing up my conception of how it works and the sequence of the process..
Thanks for your help ;)
EDIT: "
In few words my question is, what is the sequence of this code? user goes on the /home page that redirect on "departments" page. But what happen before this --> "List list = departmentBO.findAllDepartments();" ?;)
When the departmentBO.findAllDepartments() method is called if you look at the code it invokes the sessionFactory. That is an internal factory class in Hibernate that basically builds a transactional connection to the DB in order to run a query. You are defining the query in the createQuery method and then ultimately executing it with the list() method. These two methods are part of the database session that Hibernate has instantiated.
Departments Page -> departmentBO.findAllDepartments() -> sessionFactory -> createQuery -> list()
Or in pseudo code-ish
Departments Page -> execute findAllDepartments method -> fetch / build a database connection -> define the query -> execute the query -> Return the list!

Spring Boot + Spring Data JPA + Spring Data ElasticSearch: elastic doesn't return any results

I am new to setting up embedded Elasticsearch into my Spring Boot application where Spring Data JPA is setup with Postgres database.
Now I've also added support for Elastic Search Spring Data repositories (or so I thought). The problem is that ES searches do not return anything (JSON array is empty), whilst JPA ones work correctly.
I read that people need an index tool that runs every now and then, but I couldn't find anything related to this in the Spring Data Elastic Search documents.
Do I understand correctly that you need to index the searches from the database constantly? Is the answer provided in this topic Batch indexing Spring Data JPA entries to Elastic through Spring Data ElasticSearch the only solution:
Here is the Application class:
#SpringBootApplication
#EnableJpaRepositories(basePackages = "eu.deniss.repository")
#ComponentScan
public class SpringDataElasticsearchDemoApplication {
public static void main(String[] args) {
SpringApplication.run(SpringDataElasticsearchDemoApplication.class, args);
}
}
Person Entity class:
#Entity
#Document(indexName = "person", type = "person")
public class Person {
private Long id;
private String firstName;
private String lastName;
private String email;
private String gender;
private String ipAddress;
#Id
#org.springframework.data.annotation.Id
#Column(name = "id")
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
...
}
PersonSearchRepository class:
public interface PersonSearchRepository extends ElasticsearchRepository<Person, Long> {
}
PersonServiceImpl class:
#Service
public class PersonServiceImpl implements PersonService {
private final PersonRepository personRepository;
private final PersonSearchRepository personSearchRepository;
private final PersonMapper personMapper;
private static final Logger log = Logger.getLogger(PersonServiceImpl.class);
public PersonServiceImpl(PersonRepository personRepository, PersonSearchRepository personSearchRepository, PersonMapper personMapper) {
this.personRepository = personRepository;
this.personSearchRepository = personSearchRepository;
this.personMapper = personMapper;
}
...
#Override
#Transactional(readOnly = true)
public Page<PersonDTO> search(String query, Pageable pageable) {
log.info("Request to search for a page of People with a query " + query);
Page<Person> result = personSearchRepository.search(queryStringQuery(query), pageable);
return result.map(person -> personMapper.personToPersonDTO(person));
}
}
PersonController class:
#RestController()
#RequestMapping("/api")
public class PersonController {
private final PersonService personService;
private final Logger log = LoggerFactory.getLogger(PersonController.class);
private static final String ENTITY_NAME = "person";
public PersonController(PersonService personService) {
this.personService = personService;
}
#GetMapping("/_search/people")
public ResponseEntity<List<PersonDTO>> searchPeople(#RequestParam String query, Pageable pageable) throws URISyntaxException {
log.info("REST request to search for a page of Appointments for query {} ", query);
Page<PersonDTO> page = personService.search(query, pageable);
HttpHeaders headers = PaginationUtil.generateSearchPaginationHttpHeaders(query, page, "/api/_search/people");
return new ResponseEntity<>(page.getContent(), headers, HttpStatus.OK);
}
}
The answer was quite simple.
I had to do a batch job of querying current entities from a database and saving them to Elastic Search by using
personSearchRepository.save(person);

Categories

Resources