Skip to content

Commit

Permalink
Unit tests for user service (find user by username) and contact servi…
Browse files Browse the repository at this point in the history
…ce (find contacts by username) written along with some other minor refactoring.
  • Loading branch information
Badri Paudel committed Mar 16, 2024
1 parent d09c8cb commit bf5caa6
Show file tree
Hide file tree
Showing 7 changed files with 206 additions and 8 deletions.
1 change: 1 addition & 0 deletions src/main/java/info/keeper/controllers/AdminController.java
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ public AdminController(AdminRepository adminRepository, UserRepository userRepos

@GetMapping("/index")
public String showAdminPage(Principal principal, Model model) {
// In Prod app, put all the business login inside of the service and just use that in the controller.
User user = userRepository.findUserByUsername(principal.getName());
model.addAttribute("user", user);
model.addAttribute("adminMessage", new AdminMessage());
Expand Down
13 changes: 6 additions & 7 deletions src/main/java/info/keeper/controllers/ContactController.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@
import info.keeper.repositories.ContactRepository;
import info.keeper.repositories.UserRepository;
import info.keeper.service.ContactService;
import info.keeper.service.UserService;
import info.keeper.utils.Message;
import org.springframework.core.io.ClassPathResource;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Controller;
import org.springframework.ui.Model;
Expand All @@ -34,11 +34,13 @@ public class ContactController {
private final UserRepository userRepository;
private final ContactRepository contactRepository;
private final ContactService contactService;
private final UserService userService;

public ContactController(UserRepository userRepository, ContactRepository contactRepository, ContactService contactService) {
public ContactController(UserRepository userRepository, ContactRepository contactRepository, ContactService contactService, UserService userService) {
this.userRepository = userRepository;
this.contactRepository = contactRepository;
this.contactService = contactService;
this.userService = userService;
}

// show add Note form
Expand Down Expand Up @@ -108,11 +110,8 @@ public String addContact(@Valid @ModelAttribute("contact") Contact contact, Bind
public String findContactsByUser(@PathVariable("pageNumber") int pageNumber, Pageable pageable,
Model model, Principal principal) {

User user = userRepository.findUserByUsername(principal.getName());

//Pageable has current page and number of notes per page
Pageable pageable1 = PageRequest.of(pageNumber, 5); // 5 notes per page
Page<Contact> allContacts = contactRepository.findContactsByUser(user.getId(), pageable1);
User user = userService.getUserByUsername(principal.getName());
Page<Contact> allContacts = contactService.findContactsByUser(principal.getName(), pageNumber);

model.addAttribute("title", "All Of your Notes || Information Keeper");
model.addAttribute("user", user);
Expand Down
13 changes: 12 additions & 1 deletion src/main/java/info/keeper/service/ContactService.java
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import info.keeper.utils.CsvUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

Expand Down Expand Up @@ -38,5 +41,13 @@ public boolean saveAllImportedContactsToDatabase( MultipartFile file, Principal
logger.error("Something went wrong while importing contacts : ");
return false;
}
}
}

public Page<Contact> findContactsByUser(String username, int pageNumber ) {
User user = userRepository.findUserByUsername(username);
//Pageable has current page and number of notes per page
Pageable pageable = PageRequest.of(pageNumber, 5); // 5 notes per page
Page<Contact> allContacts = contactRepository.findContactsByUser(user.getId(), pageable);
return allContacts;
}
}
20 changes: 20 additions & 0 deletions src/main/java/info/keeper/service/UserService.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package info.keeper.service;

import info.keeper.models.User;
import info.keeper.repositories.UserRepository;
import org.springframework.stereotype.Service;

@Service
public class UserService {
private UserRepository userRepository;

public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public User getUserByUsername(String username) {
User user = userRepository.findUserByUsername(username);
return user;
}
}

3 changes: 3 additions & 0 deletions src/test/java/info/keeper/controllers/HomeControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import info.keeper.repositories.UserRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
Expand Down Expand Up @@ -61,6 +62,7 @@ void tearDown() {
* More the coverage, the better it will be.
*/
@Test
@DisplayName("Ensure that GET: / returns the expected response with status and title of the page")
void testHomePage() throws Exception {
assertThat(homeController).isNotNull();
// assert homeController != null; // => same as above
Expand All @@ -71,6 +73,7 @@ void testHomePage() throws Exception {

@Test
void testLoginPage() {

}

@Test
Expand Down
88 changes: 88 additions & 0 deletions src/test/java/info/keeper/service/ContactServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
package info.keeper.service;

import info.keeper.models.Contact;
import info.keeper.models.User;
import info.keeper.repositories.ContactRepository;
import info.keeper.repositories.UserRepository;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import static org.assertj.core.api.Assertions.assertThat;

import java.util.ArrayList;
import java.util.List;

@SpringBootTest
class ContactServiceTest {
@Mock
private ContactRepository contactRepository;
@Mock
private UserRepository userRepository;

@InjectMocks
private ContactService serviceUnderTest;

private User user;
private Integer userId;
private String username;
private Integer pageNumber;
private Long expectedNumberOfContacts;

@BeforeEach
void setUp() {
// Any setup before each test.
username = "john.doe@gmail.com";
userId = 101;
pageNumber = 1;
expectedNumberOfContacts = 5L;
user = new User();
user.setEmail(username);
user.setId(userId);
}
@AfterEach
void cleanUp() {
// Any cleanup after each test.
}

@Test
void findContactsByUser() {
Mockito.when(userRepository.findUserByUsername(username)).thenReturn(user);
Pageable pageable = PageRequest.of(pageNumber, 5);
Mockito.when(contactRepository.findContactsByUser(userId, pageable)).thenReturn(getContactsWithPaginationForUser());
Page<Contact> allContacts = serviceUnderTest.findContactsByUser(username, pageNumber);
assertThat(allContacts.getTotalElements()).isEqualTo(expectedNumberOfContacts);
Assertions.assertAll("Assert that returned elements have My Contact Name in name and 123456789 in phone number",
() -> {
allContacts.getContent().forEach( contact -> {
Assertions.assertTrue(contact.getName().contains("My Contact Name") &&
contact.getPhoneNumber().contains("123456789"));
});
}
);
}

private Page<Contact> getContactsWithPaginationForUser() {
List<Contact> contacts = new ArrayList<>();
for (int i = 1; i <= 5; i++) {
String contactName = "My Contact Name - " + i;
String phoneNumber = "123456789" + i;
Contact contact = new Contact();
contact.setId(i);
contact.setName(contactName);
contact.setPhoneNumber(phoneNumber);
contacts.add(contact);
}
// Create a mock Page object containing the contacts
PageImpl<Contact> pagedContacts = new PageImpl<>(contacts);
return pagedContacts;
}
}
76 changes: 76 additions & 0 deletions src/test/java/info/keeper/service/UserServiceTest.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
package info.keeper.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.Mockito.*;

import info.keeper.models.User;
import info.keeper.repositories.UserRepository;
import org.junit.jupiter.api.*;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.springframework.boot.test.context.SpringBootTest;

/**
* REF: https://www.baeldung.com/java-spring-mockito-mock-mockbean (Mockito.Mock vs @Mock syntax)
* REF : https://stackoverflow.com/questions/16467685/difference-between-mock-and-injectmocks (@InjectMocks and @Mock)
*/
@SpringBootTest
class UserServiceTest {
// This UserRepository will be mocked (for some method of it, we will be returning the result of the mock and not the real db call)
@Mock
private UserRepository userRepository;

/**
* Mark a field on which injection should be performed.
* @InjectMocks creates the instance of the class and injects the mocks that are
* created with the @Mock (or @Spy) annotations into this instance.
* REF: https://stackoverflow.com/questions/16467685/difference-between-mock-and-injectmocks
*/
@InjectMocks
private UserService userService; // Service under test, all services ( or repo ..) with Mock annotations applied will be injected into it.

// Define fields.
private static User user;
private static String username;

@BeforeAll
static void setUpData() {
username = "badripaudel77@gmail.com";
user = new User();
user.setEmail(username);
}

@BeforeEach
void setUp() {
// Any setup before each test.
}
@AfterEach
void cleanUp() {
// Any cleanup after each test.
}

@Test
@DisplayName("Test that getUserByUsername() of the service returns correct user.")
void testGetUserByUsername() {
/**
* Define mock behavior for userRepository
* That is, when user userRepository.findUserByUsername() is called, return the user (mock it, instead of calling the db)
*/
when(userRepository.findUserByUsername(username)).thenReturn(user);
// Mockito.when(userRepository.findUserByUsername(username)).thenReturn(user);
// Call the method under test
User userByUsername = userService.getUserByUsername(username);

// Verify that the userRepository method was called with the correct parameter
verify(userRepository).findUserByUsername("badripaudel77@gmail.com");

// Verify that the returned user is the same as the expected user
assertThat(userByUsername).isEqualTo(user);
assert userByUsername.getEmail().equals(user.getEmail()) == true;
}

@AfterAll
static void tearDown() {
// Any cleanup after all the tests are executed.
}
}

0 comments on commit bf5caa6

Please sign in to comment.