SDLC
1. Planning and estimation
2. Requirement and Analysis - what actually we are developing in the project
3. Design - how actually we are developing the project
- spend 40% of work
4. Coding - convert design into code - spend 20% of work
5. Testing - test ur appl to satisfy the client requirement - tester - spend 40% of work
6. Implementation
7. Maintainence
Unit testing
- Test individual classes and their methods by the developers at time of coding
JUnit 5 (Jupiter)- perform unit testing in Java
NUnit - perform unit testing in .NET
- We have to manually configure Junit and Mockito dependency in pom.xml
Junit with Mockito
- open source testing framework used to create mock objects
- Every Springboot appl we create is based on MVC archiecture (ie) controller,service, repository. If we write test case for controller prg, first request hits the controller, then service, then repository, then database. But it is not good practise to hit db at time of testing
When we create any Springboot project by default it comes with spring-boot-starter-test dependency where we can write test cases for ur springboot appl
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
spring-boot-starter-test = junit5 + mockito + hamcrest
client request - controller - service - repository - database
@RunWith(MockitoJunitRunner.class) - JUnit4 to support mockito based annotation
@ExtendWith(MockitoExtension.class) - JUnit5 to support mockito based annotation
Mockito with controller prg
@WebMvcTest - write test cases for @Controller/@RestController, loads only web layer includes security, interceptors for handling request and response
MockMvc class which is a part of spring framework which helps in testing controller by explicitly starting the server which will be used along with @WebMvcTest
@MockBean - used to add mock object in spingboot, but it is used before springboot3.x
@MockitoBean - used to add mock object in spingboot, from springboot3.x onwards
Builder design pattern - used to create/build an object, lombok supports with @Builder
Stubbing of methods - how mock object will accept the input and return the output
- when() + thenReturn()
- doReturn() + when()
ArgumentMatchers - instead of hardcoding the input value we can pass it dynamically using
- anyInt(), anyString(), anyBoolean(), anyChar(), anyFloat()
- any(Class)
import static org.hamcrest.CoreMatchers.is;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import java.util.ArrayList;
import java.util.List;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.http.MediaType;
import org.springframework.mock.web.MockHttpServletResponse;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pack.SpringBootJPA.controller.MovieController;
import com.pack.SpringBootJPA.entity.Movie;
import com.pack.SpringBootJPA.entity.UserInfo;
import com.pack.SpringBootJPA.security.JwtAuthFilter;
import com.pack.SpringBootJPA.security.JwtService;
import com.pack.SpringBootJPA.service.MovieService;
@ExtendWith(MockitoExtension.class)
@WebMvcTest(value=MovieController.class)
@AutoConfigureMockMvc(addFilters = false) //disable security while testing
public class TestMovieController {
@Autowired
MockMvc mockMvc; //explicitly start the server while running test case
@MockitoBean
MovieService movieService;
@MockitoBean
JwtService jwtService;
@MockitoBean
AuthenticationManager authenticationManager;
@MockitoBean
JwtAuthFilter authFilter;
@Autowired
ObjectMapper mapper; //read and write json in string format
@Test
public void testCreateMovie() throws Exception {
//Movie movie=new Movie(100,"Friends","English","Comedy",5);
Movie movie=Movie.builder().id(100).name("Friends")
.language("English").type("Comedy").rating(5).build();
//when(movieService.createMovie(movie)).thenReturn(movie);
//doReturn(movie).when(movieService.createMovie(movie));
when(movieService.createMovie(any(Movie.class))).thenReturn(movie);
ResultActions response=mockMvc.perform(post("/api/movie")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(movie))
);
response.andDo(print())
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name",is(movie.getName())))
.andExpect(jsonPath("$.language",is(movie.getLanguage())));
}
@Test
public void testGetAllMovies() throws Exception {
Movie movie=Movie.builder().id(100).name("Friends")
.language("English").type("Comedy").rating(5).build();
Movie movie1=Movie.builder().id(101).name("LostWorld")
.language("English").type("Thriller").rating(4).build();
List<Movie> movieList=new ArrayList<>();
movieList.add(movie);
movieList.add(movie1);
when(movieService.getAllMovies()).thenReturn(movieList);
ResultActions response=mockMvc.perform(get("/api/movie"));
MockHttpServletResponse res=response.andReturn().getResponse();
Movie[] mov=mapper.readValue(res.getContentAsString(), Movie[].class);
assertEquals(mov[0].getName(),movie.getName());
assertEquals(mov[1].getType(),movie1.getType());
}
@Test
public void testGetMovieById() throws Exception {
Movie movie=Movie.builder().id(100).name("Friends")
.language("English").type("Comedy").rating(5).build();
when(movieService.getMovieById(anyInt())).thenReturn(movie);
ResultActions response=mockMvc.perform(get("/api/movie/{movid}",100));
MockHttpServletResponse res=response.andReturn().getResponse();
Movie mov=mapper.readValue(res.getContentAsString(), Movie.class);
assertEquals(movie.getType(),mov.getType());
}
@Test
public void testAddNewUser() throws Exception {
UserInfo userInfo=new UserInfo(1000,"Ram",ram@gmail.com,"abcd","ADMIN");
when(movieService.addNewUser(any(UserInfo.class)))
.thenReturn("User added successfully");
ResultActions response=mockMvc.perform(post("/api/new")
.contentType(MediaType.APPLICATION_JSON)
.content(mapper.writeValueAsString(userInfo))
);
response.andDo(print())
.andExpect(status().isOk());
}
}
Mockito with service prg
@SpringBootTest - load entire application context
@InjectMocks - used which class to be tested
import static org.assertj.core.api.Assertions.assertThat;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.anyInt;
import static org.mockito.Mockito.when;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.context.bean.override.mockito.MockitoBean;
import com.pack.SpringBootJPA.entity.Movie;
import com.pack.SpringBootJPA.entity.UserInfo;
import com.pack.SpringBootJPA.repository.MovieRepository;
import com.pack.SpringBootJPA.repository.UserInfoRepository;
import com.pack.SpringBootJPA.service.MovieService;
@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class TestMovieService {
//@Autowired
@InjectMocks
MovieService movieService;
@MockitoBean
MovieRepository movieRepo;
@MockitoBean
UserInfoRepository userRepo;
@MockitoBean
PasswordEncoder encoder;
@Test
public void testCreateMovie() {
Movie movie=Movie.builder().id(100).name("Friends")
.language("English").type("Comedy").rating(5).build();
when(movieRepo.save(any(Movie.class))).thenReturn(movie);
assertThat(movieService.createMovie(movie)).isEqualTo(movie);
}
@Test
public void testGetAllMovies() {
Movie movie=Movie.builder().id(100).name("Friends")
.language("English").type("Comedy").rating(5).build();
Movie movie1=Movie.builder().id(101).name("LostWorld")
.language("English").type("Thriller").rating(4).build();
List<Movie> movieList=new ArrayList<>();
movieList.add(movie);
movieList.add(movie1);
when(movieRepo.findAll()).thenReturn(movieList);
assertThat(movieService.getAllMovies()).isEqualTo(movieList);
}
@Test
public void testGetMovieById() {
Movie movie=Movie.builder().id(100).name("Friends")
.language("English").type("Comedy").rating(5).build();
when(movieRepo.findById(anyInt())).thenReturn(Optional.of(movie));
assertThat(movieService.getMovieById(100)).isEqualTo(movie);
}
@Test
public void testAddNewUser() {
UserInfo userInfo=new UserInfo(1000,"Ram",ram@gmail.com,"abcd","ADMIN");
when(userRepo.save(userInfo)).thenReturn(userInfo);
assertThat(movieService.addNewUser(userInfo)).isEqualTo("User added Successfully");
}
}
@ExtendWith(MockitoExtension.class)
@SpringBootTest
public class TestUserInfoUserDetailsService {
@MockitoBean
UserInfoRepository userRepo;
@InjectMocks
UserInfoUserDetailsService userService;
UserInfo userInfo;
@BeforeEach
public void setUp() {
userInfo = new UserInfo();
userInfo.setName("Test");
userInfo.setEmail(test@gmail.com);
userInfo.setPassword("abcd");
userInfo.setRole("ROLE_ADMIN");
}
@Test
public void testLoadUserByUsernameExists() {
when(userRepo.findByName(anyString())).thenReturn(Optional.of(userInfo));
UserDetails userDetails=userService.loadUserByUsername(userInfo.getName());
assertNotNull(userDetails);
assertEquals("Test",userDetails.getUsername());
assertEquals("abcd",userDetails.getPassword());
assertEquals(1,userDetails.getAuthorities().size());
}
@Test
public void testLoadUserByUsernameNotExists() {
when(userRepo.findByName(anyString())).thenReturn(Optional.empty());
UsernameNotFoundException exception=assertThrows(UsernameNotFoundException.class,() -> userService.loadUserByUsername("Ram"));
assertEquals("User not found: Ram",exception.getMessage());
}
}