Junit
자바용 유닛 테스트 프레임워크
Spring boot에서 사용하기
Spring boot앱을 만들면 추가 되는 org.springframework.boot:spring-boot-starter-test 의존성에 junit이 포함 되어 있기 때문에 별도로 의존성을 추가 할 필요는 없음.
테스트를 시작하기 앞서 User라는 도메인 객체와 그에 맞게 Repository, Service, Controller를 간단하게 구현 해 두었고, 개발 환경은 IntelliJ를 기준으로 하였음.
@NoArgsConstructor
@ToString
@Builder
@Setter
@Getter
@Entity
@Table(name = "users")
public class User {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
private long id;
@Column(nullable = false, unique = true, length = 30)
private String name;
@Column(length = 100)
private String description;
}
1. Repository 테스트 하기
만들어둔 Repository 인터페이스에서 Ctrl + Shift + T (Windows OS 기준) 를 누르면 테스트 클래스를 만들 수 있다.
Junit5에서는 @RunWith 어노테이션 대신 @ExtendWith(SpringExtend.class)를 사용하며, @DataJpaTest 어노테이션을 사용하면 JPA와 관련된 컴포넌트만 로드된다.
@ExtendWith(SpringExtension.class)
@DataJpaTest
class UserRepositoryTest {
@Autowired
private UserRepository userRepository;
@Test
void test_User_save() {
final User user = User.builder()
.id(1)
.description("설명")
.name("zkdlu")
.build();
final User savedUser = userRepository.save(user);
assertEquals(user.getName(),
savedUser.getName());
}
@Test
void test_User_list() {
User user = User.builder()
.id(2)
.description("설명")
.name("zkdlu")
.build();
userRepository.save(user);
List<User> users = userRepository.findAll();
assertEquals(users.size(), 1);
}
}
테스트를 실행하면서 ‘constructor User in class User cannot be applied to given types; @Builder’ 라는 예외가 발생하였는데, 이는 Lombok의 @Builder 와 @NoArgsConstructor 어노테이션을 함께 사용해서 발생하는 예외 메시지이다.
@Builder는 생성자가 없을 경우 @AllArgsConstructor(access = AccessLevel.PACKAGE) 가 적용되는데, 생성자가 있을 경우에는 모든 인자를 받는 생성자가 필요하다.
@AllArgsConstructor 어노테이션을 추가하면 해결 할 수 있다.
2. Service 테스트 하기
Mockito를 이용해 Repository와 의존성이 없도록 테스트를 한다.
@ExtendWith(SpringExtension.class)
class UserServiceTest {
private UserRepository userRepository;
private UserService userService;
@BeforeEach
void setUp() {
userRepository = Mockito.mock(UserRepository.class);
userService = new UserService(userRepository);
final User user = User.builder()
.id(1L)
.name("zkdlu")
.description("안녕")
.build();
Mockito.when(userRepository.findByName("zkdlu"))
.thenReturn(Optional.of(user));
}
@Test
void getUsers() {
User findUser = userService.findByName("zkdlu").get();
assertEquals(findUser.getId(), 1L);
assertEquals(findUser.getName(), "zkdlu");
}
}
3. API 테스트 하기
@ExtendWith(SpringExtension.class)
@WebMvcTest(UserController.class)
class UserControllerTest {
@Autowired
private MockMvc mvc;
@MockBean
private UserService userService;
@Test
void test_getUsers() throws Exception {
final ResultActions actions = mvc.perform(get("/users/{id}", 1L)
.contentType(MediaType.APPLICATION_JSON))
.andDo(print());
actions
.andExpect(status().isOk())
.andExpect(jsonPath("id").value(1L))
.andExpect(jsonPath("name").value("zkdlu"))
.andExpect(jsonPath("description").value("hello"));
}
}
테스트를 생성하면서 빈 생성이 안되면서 예외가 발생했는데 구체적인 이유는 추후 알아가야겠음.