[Junit] 단위 테스트 하기

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

테스트를 생성하면서 빈 생성이 안되면서 예외가 발생했는데 구체적인 이유는 추후 알아가야겠음.