Skip to content

Latest commit

 

History

History
66 lines (41 loc) · 6.6 KB

231012.md

File metadata and controls

66 lines (41 loc) · 6.6 KB

테스트

통테에도 모킹을 쓴다!

MessageService 클래스는 다음 세 필드에 대한 의존성을 가진다.

public class MessageService {
	private final MessageTemplateRepository messageTemplateRepository;
	private final CenterRepository centerRepository;
	private final DefaultMessageService defaultMessageService;
}

이 중 defaultMessageService는 외부 모듈로 해당 모듈의 기능을 사용하여 메세지를 전송하게 된다. 통합 테스트에서는 mocking을 하지 않는다고 알려져 있지만 이처럼 외부 모듈같이 테스트하기 어려운 경우에는 모킹하여 의존성을 끊어내고, stubbing으로 우리가 원하는 동작을 가정하여 테스트를 수행하게 된다.

테스트에서는 필드 주입 써도 되는 이유

아마 스프링을 배운 사람이라면 변경 가능성이나 순환 참조나 불변성 등을 이유로 생성자 주입을 쓰라는 말을 귀에 딱지가 박히도록 들었을 것이다. 하지만 테스트에서는 필드 주입을 써도 괜찮다. 왜냐면 필드 주입의 단점이 발생하는 상황이 테스트에서는 발생하지 않기 때문이다.

  1. 별다른 방법이 없다. junit에서 테스트할 대상을 전달받기 위해서는 @Autowired를 써야 한다.
  2. 생성자 주입을 쓰는 이유는 크게 불변성과 순환참조 등을 이유로 들 수 있다. 하지만 테스트에서는 junit 외에는 아무도 테스트를 인스턴스화하려고 하지 않는다.
  3. 스프링도 인정한 방식이다. spring-data-jpa는 테스트에서 이 방식을 사용한다. (https://github.com/spring-projects/spring-data-jpa/blob/35dc37124f21b97280246005bdcd2b2cf076050e/spring-data-jpa/src/test/java/org/springframework/data/jpa/repository/UserRepositoryTests.java#L99)

https://stackoverflow.com/questions/46094725/is-field-injection-legitimate-in-a-test-class-for-a-spring-data-repository

SpyBean을 주입하는 방법 헷갈리지 않기

Spy, Mock과 유사한 개념으로 SpyBean, MockBean이 있다. 두 그룹의 차이는 스프링 빈이냐 아니냐다. Spy와 Mock은 mockito framework가 가지고 있는 것으로 스프링처럼 알아서 의존성 주입을 해주지 않는다. Spy와 Mock을 생성자 파라미터로 주입하여 인스턴스화해주는 @InjectMocks의 코멘트를 보자.

Again, note that @InjectMocks will only inject mocks/spies created using the @Spy or @Mock annotation.
...
Mockito is not an dependency injection framework, don't expect this shorthand utility to inject a complex graph of objects be it mocks/spies or real objects.

요약하자면 @InjectMocks는 mock과 spy 어노테이션이 달린 객체들만 주입해준다는 것, 그리고 Mockito는 스프링과 같은 DI 프레임워크가 아니기 때문에, 이 간단한 유틸리티로 mock / spy / 진짜 객체들로 이루어진 복잡한 그래프를 가진 객체를 주입해주기를 기대하면 안된다는 것이다.

즉 InjectMocks는 스프링 컨테이너로 관리되지 않는 객체들의 간단한 의존관계를를 주입 유틸리티를 사용하여 해결하는 데에 목적이 있다. 그렇다면 복잡한 의존관계는 어떻게 할까? 당연히 스프링 컨테이너다. 흔히 말하는 엔터프라이즈급 애플리케이션들은 정말정말 복잡한 객체 간 의존관계에 있는데, 컨테이너 기술이 가지는 IoC/DI 컨셉이 이걸 해결하는 데 특화되어 있기 때문에 스프링 같은 것들이 히트를 쳤다.

결론은 뭐냐면 SpyBean, MockBean을 사용하는 경우 스프링 프레임워크에 등록되어 관리되기 때문에 그 이후부터는 일반적으로 스프링 빈을 테스트하는 방식대로 @Autowired 를 사용하면 된다. 우리의 경우 DefaultMessageService 가 외부 모듈이므로, 이 부분만 @MockBean 으로 처리한다. 다른 의존관계 (레포지터리 빈) 들은 어차피 @SpringBootTest 를 사용하고 있으므로 알아서 주입된다. 그리고, MessageService 에 대하여 @Autowired 로 필드 주입을 받으면 끝이다! 괜히 레포지터리 빈을 SpyBean 으로 만드는 뻘짓을 할 필요가 없다.

Today-I-Heard

rpc와 grpc

msa 환경에서 서로 다른 언어로 개발된 서비스에 대하여, 언어에 구애받지 않고 통일된 방식으로 원격 프로시저를 호출할 수 있게 하는 방법이다. grpc는 google이 개발한 rcp 프레임워크로, HTTP/2 기반으로 양방향 통신이 가능하며 protobuf를 사용하기 때문에 더 빠르게 데이터를 전송할 수 있다. (https://grpc.io/docs/what-is-grpc/core-concepts/)

flyway로 DB 스키마 형상관리하기

피쳐를 쳐내다보면 디비 스키마에 잦은 변경사항이 발생한다. 기존에는 이 변경사항을 슬랙 채널에 테이블 ddl을 공유하는 식으로 관리하고 있었다. 이 방식의 가장 큰 단점은 휴먼 에러다. A 기능을 작업하면서 a 테이블을 추가하고, 해당 테이블에 대한 ddl을 뽑아서 잘 공유가 된다면 문제가 없지만, 가끔 b 테이블의 칼럼명을 수정하게 되는 경우가 있다. 피쳐 개발 기간이 늘어지게 되면 이 변경사항을 놓치게 되는 경우가 있다. 하루종일 쥐잡듯이 에러로그를 뒤지다가 운영디비에 컬럼명이 하나 바뀌어있어서 발생했던 이슈인 것을 깨닫는다면... 그 허탈함이란 이루 말할 수 없는 것이다.

그런 생각을 하게 되었다. 피쳐에서 디벨롭으로 넣을 때 데이터베이스 변경사항도 같이 트래킹하여 리뷰할 수 있으면 얼마나 좋을까? 그리고, 프로덕션으로 배포할 때 개발디비의 변경사항을 운영디비로 반영할 때 이를 CI/CD 파이프라인에 통합시킬 수 있다면 얼마나 좋을까?

내가 불편했다면 이미 해결방법이 있거나 내가 뭔가를 잘못 하고 있거나 둘 중 하나다. 다행히 이번에는 전자였고, 이걸 해결해주는 도구가 flyway다. 감사하게도 flyway 공식 문서에는 도커와 github actions 스크립트 작성을 통해 데이터베이스 변경사항을 배포하는 방법에 대해서 잘 설명하고 있다.

https://documentation.red-gate.com/fd/github-dockerized-yml-pipeline-using-github-actions-188645384.html

이걸 보면 된다. 곧 시험기간이라 당장 도입하는 것은 어렵겠지만 현재 슬랙을 통한 작업방식이 너무너무 불편했기에 빠르게 해결했으면 하는 바람...

테스트 작성

https://howtodoinjava.com/best-practices/unit-testing-best-practices-junit-reference-guide/

테스트 작성법