2022/02/13 한 번에 끝내는 Spring 완.전.판 초격차 패키지 Online.
테스트를 잘 하는 방법
강사님께서 실무에서 겪었던 테스트 기능이나 경험들을 강의 해주셨다.
- myBatis에서는 테스트하기가 상당히 까다로움
- 그 후 시간이 지나 JPA를 하게 되고, 쿼리가 아닌 자바 코드에 로직이 많이 담기게 됨
- 유지보수성의 극적인 향상(쿼리로는 다향성이나 디자인패턴 전략 등을 하기 어렵거나 불가능)
- 자바코드에 담긴 로직은 테스트하기 쿼리에 담긴 로직에 비해 상대적으로 편리함
테스트를 잘 하기 위한 기반
-
클래스나 메서드가 SRP(단일 책임 원칙)를 잘 지키고, 크기가 적절히 작아야 함
- 그래야 테스트를 집중력 있게 만들 수 있고 한 메서드에 너무 많은 테스트를 수행하지 않아도 됨
- 이게 테스트를 하는 것의 장점이 되기도 함(테스트를 하면 자연스럽게 역할이 확인되면서 쪼개짐)
-
적절한 Mocking을 통한 격리성 확보
- 단위 테스트가 만능은 아니지만, 위의 SRP처럼 해당 메서드의 역할을 정확히 테스트하려면 주변 조건을 적절히 통제해야 함
-
당연히 잘 돌겠지라는 생각말고 꼼꼼히 테스트 && 너무 과도하게 많은 테스트와 코드량이 생기지 않도록 적절히 끊기
- 테스트 코드도 코드 리뷰 시에 적절한 테스트를 하는지 확인 필요
-
테스트 코드 개선을 위한 노력
- 테스트코드도 리팩토링 필요
- 테스트코드의 기법들도 지속적인 고민 필요(통합테스트 등)
Junit,Mockito 설명
Junit
순수하게는 Java의 Unit테스트를 위한 프레임워크이다.
testImplementation 'org.springframework.boot:spring-boot-starter-test'
여기안에 Jnit5도 들어가 있다.!
일반적인 테스트 구조
@Test
public void testSomething(){
String result ="hello"+"world!";
assertEquals("hello world!",result);
}
org.junit.jupiter.api.Assertions.*
JUnit에서 가장 많이 사용되는 검증 도구 중 하나
assertEquals(예상되는값,실제값); 이런 형식으로 사용한다.
Junit에서 스프링에서 빈으로 등록하게 될 서비스들을 쉽게 등록하기 위해서 @SpringBootTest애노테이션을 추가한다.
@SpringBootTest
우리 애플리케이션을 직접띄우는것과 유사하게 테스트할 때 기본적으로 모든 빈을 띄워서 실제 실행환경을 만들어서 테스트 환경을 구축하게 도와준다
기본적으로 통합테스트라고 말을 하게 된다.
동작을 하면 우리가 세팅한 애플리케이션이 동작을 하고 테스트를 수행하게 된다.
결과화면
테스트 코드 작성
@SpringBootTest
class DMarkerServiceTest {
@Autowired
private DMarkerService dMarkerService;
@Test
public void testSomething() {
dMarkerService.createDeveloper(CreateDeveloper.Request.builder()
.developerLevel(DeveloperLevel.SENIOR)
.developerSkillType(DeveloperSkillType.FRONT_END)
.experienceYears(12)
.memberId("memberId")
.name("name")
.age(32)
.build());
List<DeveloperDto> allEmployedDevelopers = dMarkerService.getAllEmployedDevelopers();
System.out.println(allEmployedDevelopers);
}
}
이렇게하면 격리성이 떨어지고 DB에 데이터가 있어야 테스트를 할 수 있다는 문제점이 있다.
-> 해결방법은 격리성을 올리수 있는 방법 Mocking이다.
Mockito
격리성을 올릴 수 있는 방법
@SpringBootTest 애노테이션을 삭제하고
@ExtendWith(MockitoExtension.class)을 추가한다.
Mockito Test
@Autowired대신에 @InjectMocks 애노테이션을 붙여준다
@InjectMocks는 가짜를 DMakerService에 Inject해준다.
DmakerService에는 2개의 Dependency가 있다. 이것들을 @Mock으로 추가해준다.
@Mock
private DeveloperRepository developerRepository;
@Mock
private RetiredDeveloperRepository retiredDeveloperRepository;
이렇게 하면 두개의 리포지토리를 Test안에서 등록을 하게 되고 @InjectMock으로 클래스를 생성할 때 두개의 Mock을 자동으로 넣어주게 된다.
given(developerRepository.findByMemberId(anyString()))
.willReturn(Optional.of(Developer.builder()
.developerLevel(DeveloperLevel.SENIOR)
.developerSkillType(DeveloperSkillType.FRONT_END)
.experienceYears(12)
.statusCode(StatusCode.EMPLOYED)
.name("name")
.age(12)
.build()));
findByMemberId에 아무문자열을 넣어주면 아래의 응답을 주도록 mocking 해주었다.
전체코드
@ExtendWith(MockitoExtension.class)
class DMarkerServiceTest {
@Mock
private DeveloperRepository developerRepository;
@Mock
private RetiredDeveloperRepository retiredDeveloperRepository;
@InjectMocks
private DMarkerService dMarkerService;
@Test
public void testSomething() {
given(developerRepository.findByMemberId(anyString()))
.willReturn(Optional.of(Developer.builder()
.developerLevel(SENIOR)
.developerSkillType(FRONT_END)
.experienceYears(12)
.statusCode(StatusCode.EMPLOYED)
.name("name")
.age(12)
.build()));
DeveloperDetailDto developerDetail = dMarkerService.getDeveloperDetail("memberId");
assertEquals(SENIOR,developerDetail.getDeveloperLevel());
assertEquals(FRONT_END,developerDetail.getDeveloperSkillType());
assertEquals(12,developerDetail.getExperienceYears());
}
}
실행결과
성공시
실패시
Author And Source
이 문제에 관하여(2022/02/13 한 번에 끝내는 Spring 완.전.판 초격차 패키지 Online.), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dolljang/20220212-한-번에-끝내는-Spring-완.전.판-초격차-패키지-Online저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)