[4기] 백엔드 개발자 부트캠프 "오르미" ~ing/[4기] 백엔드 개발자 부트캠프 오르미 수업 복습

[4기] 108일차 TDD (Mockito)

sohee99 2024. 4. 19. 07:31

 

오늘의 학습 ! 

 

mockito에 대해 배웠는데용!!! 

 

흠 사실 어제 7시에 기절해버려서...... 이제야 올리는..ㅎㅎ..... 너무 피곤했...ㅠㅠㅋㅋㅋㅋ

 

<실습>

package com.estsoft.blog_project.tdd;


import org.junit.jupiter.api.Test;
import org.mockito.BDDMockito;
import org.mockito.Mock;
import org.mockito.Mockito;

import static org.junit.jupiter.api.Assertions.*;

public class UserTest {

    @Test
    public void testAddCoupon() {
        User user = new User("area00", "pw");
        assertEquals(0, user.getTotalCouponCount()); // 쿠폰수령전

        ICoupon coupon = Mockito.mock(ICoupon.class);
        Mockito.doReturn(true)
                 .when(coupon).isValid();

        user.addCoupon(coupon);
        assertEquals(1, user.getTotalCouponCount()); //쿠폰 수령 후
    }
}

 

public interface ICoupon {
    boolean isValid();
}

 

package com.estsoft.blog_project.tdd;

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

public class User {
    private String id;
    private  String pw;
    private List<ICoupon> couponList;

    public User(String id, String pw){
        this.id = id;
        this.pw = pw;
        couponList = new ArrayList<>();
    }

    public int getTotalCouponCount() {
        return couponList.size();
    }

    public void addCoupon(ICoupon coupon) {
        if (coupon.isValid()){
            couponList.add(coupon);
        }
    }
}

 

mockito란?

 

Mockito는 가짜 개체를 만들어줄 수 있는 테스트 라이브러리

 

spring으로 개발하다보면 여러 객체간의 의존성을 갖게 되어 단위테스트를 작성하기 힘들기 때문에,

mockito 라이브러리를 활용해 가짜 객체를 주입 시켜 가짜 객체에 원하는 결과를 stub해서 단위 테스트 진행 가능!

 

 

Mock 객체 의존성 주입

 

  1. @InjectMocks : @Mock이나 @Spy 어노테이션으로 생성한 가짜 객체를 자동으로 주입시켜주는 어노테이션
  2. @Mock : 가짜 객체를 만들어주는 어노테이션
  3. @Spy : Stub하지 않은 메소드들은 원본 메소드 그대로 사용하는 어노테이션

 

** 여기서 stub은 더미 객체가 마치 실제로 동작하는 것 처럼 보이게 만들어 놓은 객체! 

 

 

Service 계층 단위 테스트 작성하기

 

import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.stereotype.Service;

@Service
@RequiredArgsConstructor
public class UserService {
    private final UserRepository userRepository;
    private final BCryptPasswordEncoder encoder;

    public User save(AddUserRequest request) {
        return userRepository.save(new User(
                request.getEmail(), encoder.encode(request.getPassword())));
    }
}

 

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;

import org.mockito.Spy;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.*;

@ExtendWith(MockitoExtension.class)
public class UserServiceTest {

    @InjectMocks
    UserService userService;

    @Mock
    UserRepository userRepository;

    @Spy
    BCryptPasswordEncoder passwordEncoder;

    @DisplayName("회원 가입 테스트")
    @Test
    public void testSaveUser() {
        // given
        AddUserRequest addUser = new AddUserRequest("mock_email", "mock_password");
        BCryptPasswordEncoder encoder = new BCryptPasswordEncoder();
        String encryptPassword = encoder.encode(addUser.getPassword());

        doReturn(new User(addUser.getEmail(), encryptPassword))
                .when(userRepository)
                .save(any(User.class));

        // when
        User returnUser = userService.save(addUser);

        // then
        assertEquals(addUser.getEmail(), returnUser.getEmail());
        assertEquals(encryptPassword, returnUser.getPassword());

        verify(userRepository, times(1)).save(any(User.class));
        verify(passwordEncoder, times(1)).encode(any(String.class));
    }

}

 

Repository 단위 테스트 작성하기

 

@Repository
public interface UserRepository extends JpaRepository<User, Long> {
    Optional<User> findByEmail(String email);
}

 

테스트 코드 작성

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.orm.jpa.DataJpaTest;

import java.util.List;

import static org.assertj.core.api.Assertions.assertThat;

@DataJpaTest
class UserRepositoryTest {

    @Autowired
    private UserRepository userRepository;

		@DisplayName("이메일 주소로 사용자 조회")    
    @Test
    void findUserByEmail() {
        // given
        User saved = userRepository.save(user());

        // when
        User findUser = userRepository.findByEmail("mock_email").orElseThrow();

        // then
        assertThat(findUser.getEmail()).isEqualTo(saved.getEmail());
        assertThat(findUser.getPassword()).isEqualTo(saved.getPassword());
    }

    @DisplayName("사용자 목록 조회")
    @Test
    void findUser() {
        // given
        userRepository.save(user());

        // when
        List<User> userList = userRepository.findAll();

        // then
        assertThat(userList.size()).isEqualTo(1);
    }

    @DisplayName("사용자 추가")
    @Test
    void addUser() {
        // given
        User user = user();

        // when
        User savedUser = userRepository.save(user);

        // then
        assertThat(savedUser.getEmail()).isEqualTo(user.getEmail());
        assertThat(savedUser.getPassword()).isEqualTo(user.getPassword());
    }

    private User user() {
        return User.builder()
                .email("mock_email")
                .password("mock_pw")
                .build();
    }
}

 

소나 큐브까지 맛보기로 배웠는데엽.... 

 

 

솔직히 말하면 테스트 코드 자체는 어떤 개념인지는 이해했지만,

 

아직 실습때 사용하기엔 무리가 간달까요..... 

 

아직 코드작성에 집중할 필요가 있어보였어용! 

 

멘토님께서도 부가적인것이기 때문에 후순위로 미뤄놓고 스프링부트에 대해 공부를 더 한 다음 

 

테스트 코드를 중점적으로 공부해야할 듯합니당!!!! 

 

 

( 오늘 공부 적당,,히,,,ㅎㅎㅎ,,,)했구용!!

 

내일 공부도 파이팅!