일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
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 |
- EC2
- 알고리즘
- Pirogramming
- db
- JOIN
- Database
- 프림
- SQL코딩테스트
- 배포
- 구현
- 백준
- 최단경로
- BFS
- 크루스칼
- SQL
- 그래프 탐색
- MST
- 코딩테스트
- Java
- AWS
- 누적합
- 다익스트라
- django
- Baekjoon
- 자바
- OrderBy
- union find
- GROUPBY
- 피로그래밍
- 프로그래머스
- Today
- Total
NullNull
ObjectMother 패턴 적용하기 본문
ObjectMother 패턴이란?
우선 해당 패턴이 무엇인지 알아보기 위해 GTP에게 질문을 해보았다.
Q: ObjectMother 패턴이 뭐야?
A:
"Object Mother"는 소프트웨어 개발에서 사용되는 디자인 패턴 중 하나입니다. 이 패턴은 테스트를 위해 객체를 생성하고 설정하는 방법을 정의합니다. 주로 유닛 테스트나 통합 테스트에서 많이 사용됩니다.
일반적으로, 테스트를 작성할 때 객체를 생성하고 초기화하는 것은 반복적이고 번거로운 작업일 수 있습니다. 특히 테스트 케이스마다 다양한 상태의 객체가 필요할 때 이런 문제가 더 커집니다. Object Mother 패턴은 이러한 상황에서 객체 생성 및 초기화를 추상화하여 객체를 쉽게 생성하고 조작할 수 있도록 도와줍니다.
객체를 조금 더 쉽게 생성하기 위해 사용한다고 보여진다.
실제 사례에서 이 패턴을 왜 사용하는지 보자.
만약 한 개의 인스턴스를 생성하여 Unit Test를 작성한다면 아래와 같을 것이다.
package soccer.team.player;
import org.junit.jupiter.api.Assertions;
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.junit.jupiter.MockitoExtension;
import soccer.team.player.Player;
import soccer.team.player.PlayerRepositoryImpl;
import soccer.team.player.PlayerServiceImpl;
import static org.mockito.Mockito.doReturn;
@ExtendWith(MockitoExtension.class)
class PlayerServiceImplTest {
@InjectMocks
private PlayerServiceImpl playerService;
@Mock
private PlayerRepositoryImpl playerRepository;
@Test
@DisplayName("선수 create 테스트")
public void tc1() {
Player actual = new Player("HALLAND", "1999.10.18", 9, "Norway", true, 197, 77);
doReturn(actual).when(playerRepository).createPlayer(actual);
Player result = playerService.createPlayer(actual);
Assertions.assertEquals(actual, result);
}
}
그럼 인스턴스를 한 개 더 추가하면 어떻게 코드가 바뀔까?
아래를 보자
package soccer.team.player;
import org.junit.jupiter.api.Assertions;
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.junit.jupiter.MockitoExtension;
import soccer.team.player.Player;
import soccer.team.player.PlayerRepositoryImpl;
import soccer.team.player.PlayerServiceImpl;
import static org.mockito.Mockito.doReturn;
@ExtendWith(MockitoExtension.class)
class PlayerServiceImplTest {
@InjectMocks
private PlayerServiceImpl playerService;
@Mock
private PlayerRepositoryImpl playerRepository;
@Test
@DisplayName("선수 2명 create 테스트")
public void tc2() {
Player actual1 = new Player("HALLAND", "1999.10.18", 9, "Norway", true, 197, 77);
Player actual2 = new Player("DE BRYUNE", "1993.10.18", 17, "Belgium", true, 183, 70);
doReturn(actual1).when(playerRepository).createPlayer(actual1);
doReturn(actual2).when(playerRepository).createPlayer(actual2);
Player result1 = playerService.createPlayer(actual1);
Player result2 = playerService.createPlayer(actual2);
Assertions.assertEquals(actual1, result1);
Assertions.assertEquals(actual2, result2);
}
}
이처럼 인스턴스를 만들기 위해서 추가해줘야 하는 내용이 많다.
이를 간단하게 할 수 있는 패턴이 MotherPattern 이다.
사실 설명이 어렵지 구현은 간단하다.
아래 처럼 Mother 클래스를 구현하고 테스트에서 이를 사용하면 된다. static 메서드로 등록해두자.
package soccer.team.player;
import org.jeasy.random.EasyRandom;
public class PlayerMother {
static EasyRandom easyRandom;
static {
easyRandom = new EasyRandom();
}
static Player generate() {
return Player.builder()
.name(easyRandom.nextObject(String.class))
.birthday(easyRandom.nextObject(String.class))
.nationality(easyRandom.nextObject(String.class))
.nationalTeam(easyRandom.nextBoolean())
.number(easyRandom.nextInt())
.weight(easyRandom.nextInt())
.height(easyRandom.nextInt())
.build();
}
}
- 테스트 패키지에서 생성하고자 하는 객체의 Mother 클래스를 생성하고 그 안에 어트리뷰트에 랜덤한 값을 채워둔다.
- 테스트 클래스에서 해당 함수를 호출하여 임의의 값으로 세팅된 인스턴스를 만든다.
- 해당 인스턴스를 테스트에서 활용한다.
Random 라이브러리를 활용하여 임의의 값을 주어도 좋지만, EasyRandom을 사용하여 더 간단하게 MotherPattern을 구현했다.
아래는 실제 적용한 예시이다. 실제로 더 간단하게 인스턴스를 구현했다.
package soccer.team.player;
import org.junit.jupiter.api.Assertions;
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.junit.jupiter.MockitoExtension;
import soccer.team.player.Player;
import soccer.team.player.PlayerRepositoryImpl;
import soccer.team.player.PlayerServiceImpl;
import static org.mockito.Mockito.doReturn;
@ExtendWith(MockitoExtension.class)
class PlayerServiceImplTest {
@InjectMocks
private PlayerServiceImpl playerService;
@Mock
private PlayerRepositoryImpl playerRepository;
@Test
@DisplayName("MotherPattern 테스트")
public void tc3() {
Player actual1 = PlayerMother.generate();
Player actual2 = PlayerMother.generate();
doReturn(actual1).when(playerRepository).createPlayer(actual1);
doReturn(actual2).when(playerRepository).createPlayer(actual2);
Player result1 = playerService.createPlayer(actual1);
Player result2 = playerService.createPlayer(actual2);
Assertions.assertEquals(actual1, result1);
Assertions.assertEquals(actual2, result2);
}
}
안에 들어간 랜덤 값은 다음과 같다. 이처럼 쉽게 Unit Test를 위한 인스턴스를 생성할 수 있다. 테스트니까.. 쉽게 인스턴스 만들자..
'프로그래밍 언어 > JAVA' 카테고리의 다른 글
Mock? Spy? (0) | 2025.02.04 |
---|---|
간단한 Unit Test 작성하기 (0) | 2024.04.04 |
객체지향 언어의 특징과 설계 원칙 (0) | 2022.09.29 |
예외 처리 (0) | 2022.08.14 |
Abstract class vs Interface (0) | 2022.08.14 |