728x90

📌 Service 레이어 테스트

저번 퍼사드 패턴 적용기 에서
언급했던 테스트에 대해서 써보려고 한다.
바로 정리해보도록 하겠다.
이전의 Mockito 에 대해서 정리한 글이 있다.

📌 테스트 과정

일단 퍼사드 패턴을 적용함으로써
여러개의 서비스를 하나의 퍼사드가 관리해주는 형태로 작성을 했었다.

그러면서 하나의 Service <- 하나의 Repository가 되는 구조를 가지게 되었다.

여기서 @Mock이 등장하게 되었는데,

기존의 @Autowired 방식으로 사용했다면 꿈도 못꾸는 가짜 객체 주입이다.

Service service = new Service(); 해서 @Autowired된 객체를 주입할 수 있을까?

답은 아니라고 생각한다. 의존을 자동으로 주입해주기 때문에 뭘 할당할 수 없는 구조였다.
하지만 생성자 주입을 해준다면??? 얘기는 다르다.

Service service = new Service(repotisory); 가되기 때문에 @Mock으로 가짜 객체를 서비스에

주입해서 POJO 단위 테스트를 진행할 수 있게 된다.

@Service
@Transactional
public class Service {
    private final Repository repository;

    public Service(final Repository repository) {
        this.repository = repository;
    }

    public Foo findByName(final String name) {
        repository.findByName(name).orElseThrow();
    }
}
public interface Repository extends JpaRepository<Foo, Long> {
    Optional<Foo> findByName(final String name);
}
@Getter
public class Foo {
    private String name;
    private int age;

    public Foo (final String name, final int age) {
        this.name = name;
        this.age = age;
    }
}
@ExtendWith(MockitoExtension.class) //Mockito 의존성을 가져온다.
public class ServiceTest {

    @Mock
    private Repository repository;

    @InjectMocks //주입받을 클래스
    private Service service; //(Service service = new Service(repository);) 와 같은구조가 된다.

    @Test
    void test() {
        //given
        Foo foo = new Foo("테스트", 15);

        //when
        // 여기서 mockito로 가짜객체가 어떤 조건을 실행했을 때 어떤 객체를 돌려주게끔 설정해준다.
        BDDMockito.given(repository.findByName(anyString()).willReturn(Optional.ofNullable(foo));

        //then
        Foo foo = service.findByName("테스트");
        verify(service).findByName("테스트"); //service 객체의 findByName메소드에 name값이 '테스트' 인 것을 호출했는지 검증
        Assertions.assertThat(foo.getName()).isEqualTo("테스트");
        Assertions.assertThat(foo.getAge()).isEqualTo(15);
    }
}

이런식으로 POJO 테스트를 진행할 수 있다.
이 구조로 하여금 더더욱 DI가 중요하다는 것을 깨닫고
기초가 중요하다는 것을 다시금 인지하게 되었다.

@Spy, @Mock의 차이

간략하게 한줄로 설명하자면 @Spy는 실제 인스턴스를 사용,

@Mock은 가짜 인스턴스를 사용한다.

그래서 @SpyMockito.when() 이나 BDDMockito.given() 메서드 등으로 메서드의 행위를 지정해 주지 않으면

@Spy 객체를 만들 때 사용한 실제 인스턴스의 메서드를 호출한다.

그래서 @Spy는 실제 인스턴스를 필요로 하기 때문에 인스턴스를 할당 해주어야 사용이 가능하다.

이걸로 미루어 보아 두개를 상황에 따라 적절하게 엮어서 사용해줘야 한다는 것을 느낀다. 물론 적용 해볼 경험이 필요하다!!!!

728x90

+ Recent posts