Home Mock test
Post
Cancel

Mock test

Mock Test

UserServiceTest

가짜 객체는 동작을 하지 않는다. (passwordEncoder의 encode가 null)

처음에 test 코드를 작성했을 때 회원가입 로직에서 인코딩 된 pw와 인코딩 되지 않은 pw를 비교하여 검증을 하려고 했다.

하지만 encode된 pw가 제대로 값을 띄우지 못하고 계속 null이 떴고 그 이유를 알지 못했다.

아래 코드는 인코딩이 제대로 되지 않아서 user에 그냥 password 그 자체의 값을 넣어줬고

String pw = passwordEncoder.encode(signUpRequestDto.getPassword()); 값을 출력해보면 null로 출력되었다.



문제가 된 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
class UserServiceTest {
    @InjectMocks
    SignServiceImpl userService;
    @Mock
    UserRepository userRepository;
    @Mock
    PasswordEncoder passwordEncoder;
    User user;
    
        @Test
    @DisplayName("회원가입 test")
    void signUp() {
        //given
        SignUpRequestDto signUpRequestDto = new SignUpRequestDto();
        signUpRequestDto.setNickname("끼까꿍");
        signUpRequestDto.setPassword("뮤뮤");
        signUpRequestDto.setName("김철수");

        List<String> role = Collections.singletonList("ROLE_USER");
        String pw = passwordEncoder.encode(signUpRequestDto.getPassword());

        user = User.builder()
                .nickname(signUpRequestDto.getNickname())
                .name(signUpRequestDto.getName())
                .password(signUpRequestDto.getPassword())
                .roles(role)
                .build();
        when(userRepository.save(any(User.class))).thenReturn(user);
        
        //when
        userService.signUp(signUpRequestDto);
        verify(userRepository).save(any(User.class));

        //then
        assertAll( // 2가지 test
                () -> assertEquals(signUpRequestDto.getNickname(), user.getNickname()),
                () -> assertEquals(signUpRequestDto.getName(), user.getName())
        );
    }



원인

@Mock은 가짜 객체이다.

가짜 객체는 실제 서비스에 맞게 쓰려고 하면 NULL로 뜬다. → 가짜 객체는 동작을 안한다.

실제 객체를 가지고 쓴 다음 stubbing을 통해서 가짜 객체를 사용한 다음 retnrun 값을 실제 객체로 넣어줘야한다.



요약

PasswordEncoder passEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); : 실제 객체 만들기

String pw = passEncoder.encode(signUpRequestDto.getPassword()); : 실제 객체로 encoding하기

when(passwordEncoder.encode(user.getPassword())).thenReturn(pw); : 가짜 객체에 실제 객체를 return한다.
(가짜 객체로 실행했을 때 이렇게 동작해라 라고 알려줘야 한다.)



전체 코드

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 @Test
    @DisplayName("회원가입 test")
    void signUp() {
        //given
        PasswordEncoder passEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder(); // 1번
        SignUpRequestDto signUpRequestDto = new SignUpRequestDto();
        signUpRequestDto.setNickname("끼까꿍");
        signUpRequestDto.setPassword("뮤뮤");
        signUpRequestDto.setName("김철수");

        List<String> role = Collections.singletonList("ROLE_USER");
        String pw = passEncoder.encode(signUpRequestDto.getPassword()); // 2번 
        user = User.builder()
                .nickname(signUpRequestDto.getNickname())
                .name(signUpRequestDto.getName())
                .password(pw)
                .roles(role)
                .build();
        when(userRepository.save(any(User.class))).thenReturn(user);

        //when
        userService.signUp(signUpRequestDto);
        verify(userRepository).save(any(User.class));
        
        // then
        assertFalse(user.getName().isEmpty()); // 3번
    }


1번. 실제 객체

PasswordEncoder 설정 파일로 가면 아래와 같이 정의했다.

1
2
3
4
5
6
7
@Configuration
public class PasswordEncoderConfig {
    @Bean
    public PasswordEncoder passwordEncoder() {
        return PasswordEncoderFactories.createDelegatingPasswordEncoder();
    }
}

여기서 return값을 복사한 다음 실제 객체로 test코드에 작성해준다.



2번. password 인코딩

passEncoder.encode(signUpRequestDto.getPassword());

실제 객체에 encoding 후 User 객체에 값을 넣어준다.



3번. 검증

UserService 로직에서 name이 비어있는지 체크하는 코드가 작성되어있다.

해당 부분을 체크하고 마무리하였다.


참고로 test하려고 하는 로직에 없는 로직을 작성할 경우
*Please remove unnecessary stubbings or use ‘lenient’ strictness.
와 같은 에러가 뜰 수 있다.

이 부분은 아래 예시로 참고한다.





RegistryServiceTest

코드에 없는 로직을 test 코드에 작성하지 않는다.


RegistryService.java

1
2
3
4
5
6
public PagingResult getBoards(int curPage) {
    Pageable pageable = PageRequest.of(curPage - 1, PAGE_POST_COUNT);
    Page<Registry> boards = registryRepository.findAllByOrderByCreatedAtDesc(pageable);// 생성 날짜 순으로 보여주기
    List<Registry> boardList = boards.getContent(); // 조회된 데이터
    // 코드 생략
}

위 코드는 db에서 생성 날짜 순으로 페이징 된 결과를 출력시킨다.

위 로직에는 repository에 저장하는 코드가 없다.

그런데 test 코드에 객체를 저장하는 코드를 작성하면 안된다는 얘기다.


RegistryServiceTest.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
    @Test
    public void paging() {
        User user = User.builder()
                .nickname("nickname")
                .password("123456")
                .build();
        Registry registry = Registry.builder()
                .title("test")
                .main("main")
                .user(user)
                .build();
        
        // when(registryRepository.save(any())).thenReturn(registry); // 실제 코드에 없어서 기각
        
        // 이후 코드 생략
This post is licensed under CC BY 4.0 by the author.