ํตํฉ ํ ์คํธ
์ค์ ์ด์ ํ๊ฒฝ์์ ์ฌ์ฉ๋ ํด๋์ค๋ค์ ํตํฉํ์ฌ ํ
์คํธํ๋ค.
์คํ๋ง ํ๋ ์์ํฌ์์ ์ ์ฒด์ ์ผ๋ก ํ๋ก์ฐ๊ฐ ์ ๋๋ก ๋์ํ๋์ง ๊ฒ์ฆํ๊ธฐ ์ํด ์ฌ์ฉํ๋ค.
์ฌ๋ฌ ๋ชจ๋๋ค์ ๋ชจ์ ์ด๋ค์ด ์๋๋๋ก ํ๋ ฅํ๋์ง ํ์ธํ๋ ํ
์คํธ์ด๋ค.
์ฅ์
- ์คํ๋ง ๋ถํธ ์ปจํ ์ด๋๋ฅผ ๋์ ํ ์คํธํ๊ธฐ ๋๋ฌธ์ ์ด์ํ๊ฒฝ๊ณผ ๊ฐ์ฅ ์ ์ฌํ ํ ์คํธ๊ฐ ๊ฐ๋ฅํ๋ค.
- ์ ์ฒด์ ์ธ Flow๋ฅผ ์ฝ๊ฒ ํ ์คํธ ํ ์ ์๋ค.
๋จ์
- ์ ํ๋ฆฌ์ผ์ด์ ์ ์ค์ , ๋ชจ๋ Bean์ ๋ก๋ํ๊ธฐ ๋๋ฌธ์ ์๊ฐ์ด ์ค๋๊ฑธ๋ฆฌ๊ณ ๋ฌด๊ฒ๋ค.
- ํ ์คํธ ๋จ์๊ฐ ์ปค ๋๋ฒ๊น ์ด ์ด๋ ต๋ค.
@SpringBootTest
- ํตํฉ ํ ์คํธ๋ฅผ ์ ๊ณตํ๋ ๊ธฐ๋ณธ์ ์ธ ์คํ๋ง ๋ถํธ ํ ์คํธ ์ด๋ ธํ ์ด์ .
@SpringBootTest
@ActiveProfiles("test")
@Transactional
class ChessServiceImplTest {
// ...
}
@SpringBootTest ์ ํ๋ผ๋ฏธํฐ๋ค
- value: ํ ์คํธ๊ฐ ์คํ๋๊ธฐ ์ ์ ์ ์ฉํ ํ๋กํผํฐ ์ฃผ์ .(๊ธฐ์กด์ ํ๋กํผํฐ ์ค๋ฒ๋ผ์ด๋)
- properties : ํ ์คํธ๊ฐ ์คํ๋๊ธฐ ์ ์ {key=value} ํ์์ผ๋ก ํ๋กํผํฐ ์ถ๊ฐ.
- classes : ApplicationContext์ ๋ก๋ํ ํด๋์ค ์ง์ . (์ง์ ํ์ง ์์ผ๋ฉด @SpringBootConfiguration์ ์ฐพ์์ ๋ก๋)
- webEnvironment : ์ดํ๋ฆฌ์ผ์ด์ ์ด ์คํ๋ ๋์ ์น ํ๊ฒฝ์ ์ค์ . (๊ธฐ๋ณธ๊ฐ์ Mock ์๋ธ๋ฆฟ์ ๋ก๋ํ์ฌ ๊ตฌ๋)
โ webEnvironment
- MOCK :
ServletContainer
๋ฅผ ํ ์คํธ์ฉ์ผ๋ก ๋์ฐ์ง์๊ณ ์๋ธ๋ฆฟ์ mocking ํ ๊ฒ์ด ๋์ํ๋ค. (๋ด์ฅ ํฐ์บฃ์ด ๊ตฌ๋๋์ง ์๋๋ค.)
MockMvc๋ ๋ธ๋ผ์ฐ์ ์์ ์์ฒญ๊ณผ ์๋ต์ ์๋ฏธํ๋ ๊ฐ์ฒด๋ก์ Controller ํ ์คํ ์ฌ์ฉ์ ์ฉ์ดํ๊ฒ ํด์ฃผ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ - RANDOM_PORT : ์์์ Port Listener. EmbeddedWebApplicationContext๋ฅผ ๋ก๋ํ๋ฉฐ ์ค์ ์๋ธ๋ฆฟ ํ๊ฒฝ์ ๊ตฌ์ฑ
@ActiveProfiles
์ํ๋ ํ๋กํ์ผ ํ๊ฒฝ ๊ฐ ์ค์ ์ด ๊ฐ๋ฅํ๋ค. (ํ๋กํ์ผ ์ ๋ต)
@Transactional
ํ
์คํธ ์๋ฃ ํ ์๋์ผ๋ก Rollback ์ฒ๋ฆฌ๊ฐ ๋๋ค.
ํ์ง๋ง WebEnvironment.RANDOM_PORT, DEFINED_PORT
๋ฅผ ์ฌ์ฉํ๋ฉด ์ค์ ํ
์คํธ ์๋ฒ๋ ๋ณ๋์ ์ค๋ ๋์์ ํ
์คํธ๋ฅผ ์ํํ๊ธฐ ๋๋ฌธ์ ํธ๋์ญ์
์ด ๋กค๋ฐฑ๋์ง ์๋๋ค. (์?)
WebEnvironment.RANDOM_PORT, DEFINED_PORT
์ค์ ์น ์คํ ํ๊ฒฝ์ ๋์ด๋ค.
๋จ์ ํ ์คํธ
์ฅ์
- WebApplication ๊ด๋ จ๋ Bean๋ค๋ง ๋ฑ๋กํ๊ธฐ ๋๋ฌธ์ ํตํฉ ํ ์คํธ๋ณด๋ค ๋น ๋ฅด๋ค.
- ํตํฉ ํ ์คํธ๋ฅผ ์งํํ๊ธฐ ์ด๋ ค์ด ํ ์คํธ๋ฅผ ์งํ ๊ฐ๋ฅํ๋ค.
๋จ์
- ์์ฒญ๋ถํฐ ์๋ต๊น์ง ๋ชจ๋ ํ ์คํธ๋ฅผ Mock ๊ธฐ๋ฐ์ผ๋ก ํ ์คํธํ๊ธฐ ๋๋ฌธ์ ์ค์ ํ๊ฒฝ์์๋ ์ ๋๋ก ๋์ํ์ง ์์ ์ ์๋ค.
@WebMvcTest
- MVC๋ฅผ ์ํ ํ ์คํธ๋ก, ์น ์์์ ์์ฒญ๊ณผ ์๋ต์ ๋ํ ํ ์คํธ.
- MVC ๊ด๋ จ๋ ์ค์ ์ธ
@Controller, @ControllerAdvice, @JsonCompoent์ Filter, WebMvcConfiguer, HandlerMetohdAgumentResolver
๋ง ๋น์ผ๋ก ๋ฑ๋ก๋๋ค. (๋์คํจ์ณ ์๋ธ๋ฆฟ์์ ์ฌ์ฉ๋๋ ์์ด๋ค๋ง ์ฃผ์ ๋ฐ๋๋ค.) - ๋๋ฌธ์ Service, Repository ์ ๊ฐ์ ์น ๊ณ์ธต ์๋ ๋น๋ค์ ๋ฑ๋ก๋์ง ์์ ์์กด์ฑ๋ ๋๊ธด๋ค.
- ํ ์คํธ์ ์ฌ์ฉํ๋ ์์กด์ฑ์ด ์๋ค๋ฉด @MockBean์ผ๋ก ๋ง๋ค์ด ์ฌ์ฉํ๋ค.
@WebMvcTest(ChessController.class)
class ChessControllerTest {
private final static long CHESS_GAME_TEST_ID = 0;
@Autowired
MockMvc mockMvc;
@MockBean
ChessService chessService;
@Test
@DisplayName("๊ฒ์ ๋ฆฌ์คํธ ์กฐํ ํ
์คํธ")
void getGames() throws Exception {
List<ChessGameManager> chessGameManagers = new ArrayList<>();
ChessGameManager chessGameManager = ChessGameManagerFactory.createRunningGame(CHESS_GAME_TEST_ID);
chessGameManagers.add(chessGameManager);
given(chessService.findRunningGames()).willReturn(new ChessGameManagerBundle(chessGameManagers));
mockMvc.perform(get("/games"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.runningGames." + CHESS_GAME_TEST_ID)
.value("WHITE"));
}
@Test
@DisplayName("์๋ก์ด ๊ฒ์ ์์ ํ
์คํธ")
void gameStart() throws Exception {
ChessGameManager chessGameManager = ChessGameManagerFactory.createRunningGame(CHESS_GAME_TEST_ID);
given(chessService.start()).willReturn(chessGameManager);
mockMvc.perform(get("/game/start"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(CHESS_GAME_TEST_ID))
.andExpect(jsonPath("$.color").value("WHITE"))
.andExpect(jsonPath("$.piecesAndPositions.size()").value(32));
}
@Test
@DisplayName("๊ฒ์ ์ ์ ์กฐํ ํ
์คํธ")
void getScore() throws Exception {
ChessGameStatistics chessGameStatistics = ChessGameStatistics.createNotStartGameResult();
given(chessService.getStatistics(CHESS_GAME_TEST_ID)).willReturn(chessGameStatistics);
mockMvc.perform(get("/game/" + CHESS_GAME_TEST_ID + "/score"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.matchResult").value("๋ฌด์น๋ถ"))
.andExpect(jsonPath("$.colorsScore.size()").value(2));
}
@Test
@DisplayName("ํด๋น ๊ฒ์ ๋ก๋ฉ ํ
์คํธ")
void loadGame() throws Exception {
ChessGameManager chessGameManager = ChessGameManagerFactory.createRunningGame(CHESS_GAME_TEST_ID);
given(chessService.findById(CHESS_GAME_TEST_ID)).willReturn(chessGameManager);
mockMvc.perform(get("/game/" + CHESS_GAME_TEST_ID + "/load"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.id").value(CHESS_GAME_TEST_ID))
.andExpect(jsonPath("$.color").value("WHITE"))
.andExpect(jsonPath("$.piecesAndPositions.size()").value(32));
}
@Test
void movePiece() throws Exception {
Gson gson = new Gson();
String content = gson.toJson(new MoveRequestDto("a2", "a3"));
given(chessService.isEnd(CHESS_GAME_TEST_ID)).willReturn(false);
given(chessService.nextColor(CHESS_GAME_TEST_ID)).willReturn(Color.BLACK);
mockMvc.perform(MockMvcRequestBuilders
.post("/game/" + CHESS_GAME_TEST_ID + "/move")
.content(content).header("Content-Type", "application/json"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.end").value(false))
.andExpect(jsonPath("$.nextColor").value("BLACK"));
}
}
given - willReturn
: ํน์ ํ์์ ๋ํ ๋ฐํ ๊ฐ์ ์ง์ ํ์ฌ ์ค์ ๊ฐ์ฒด์ฒ๋ผ ๋์ํ๊ฒ ํ๋ค.
@JdbcTest
- JDBC ๊ธฐ๋ฐ ๊ตฌ์ฑ ์์์๋ง ์ด์ ์ ๋ง์ถ JDBC ํ ์คํธ ์ด๋ ธํ ์ด์
- ํ
์คํธ๋ฅผ ์ํ
JdbcTemplate
์ด ์์ฑ๋๋ค. - ๊ธฐ๋ณธ์ ์ผ๋ก ํธ๋์ญ์ ์ด ์ด๋ฃจ์ด์ง๋ค.
- in-memory database๊ฐ ์ค์ ๋๋ค.
@JdbcTest
class JdbcTemplateChessDaoTest {
private static final long DEFAULT_CHESS_GAME_ID = 1;
ChessGame chessGame;
ChessGameManager sampleGame;
private final JdbcTemplate jdbcTemplate;
private final JdbcTemplateChessDao jdbcTemplateChessDao;
@Autowired
public JdbcTemplateChessDaoTest(JdbcTemplate jdbcTemplate, @Qualifier("dataSource") DataSource dataSource) {
this.jdbcTemplate = jdbcTemplate;
this.jdbcTemplateChessDao = new JdbcTemplateChessDao(jdbcTemplate, dataSource);
}
@BeforeEach
void beforeEach() {
String sample = "RKBQKBKRPPPPPPPP................................pppppppprkbqkbkr"; // move a2 a3 ํ ๋ฒ ์งํ
chessGame = new ChessGame(DEFAULT_CHESS_GAME_ID, WHITE, true, sample);
sampleGame = ChessGameManagerFactory.loadingGame(chessGame);
}
@Test
@DisplayName("์ฒด์ค ๊ฒ์์ ์ ์ฅํ๋ค.")
void save() {
long newId = jdbcTemplateChessDao.save(chessGame);
assertThat(newId).isEqualTo(2);
}
@Test
@DisplayName("id๋ก ์ฒด์ค ๊ฒ์์ ์ฐพ๋๋ค.")
void findById() {
assertThat(jdbcTemplateChessDao.findById(DEFAULT_CHESS_GAME_ID).isPresent()).isTrue();
}
@Test
@DisplayName("์ฒด์ค ๊ฒ์ ์ ๋ณด๋ฅผ ์
๋ฐ์ดํธํ๋ค.")
void update() {
sampleGame.move(Position.of("a2"), Position.of("a4"));
jdbcTemplateChessDao.update(new ChessGame(sampleGame));
ChessGame expectedChessGame = jdbcTemplateChessDao.findById(DEFAULT_CHESS_GAME_ID).get();
ChessGameManager expectedChessGameManager = ChessGameManagerFactory.loadingGame(expectedChessGame);
Square a4 = expectedChessGameManager.getBoard().findByPosition(Position.of("a4"));
assertThat(a4.getPiece().getClass()).isEqualTo(Pawn.class);
assertThat(a4.getPiece().getColor()).isEqualTo(WHITE);
}
@Test
void findAllOnRunning() {
List<ChessGame> allOnRunning = jdbcTemplateChessDao.findAllOnRunning();
assertThat(allOnRunning.size()).isEqualTo(1);
}
@Test
void delete() {
//when
jdbcTemplateChessDao.delete(DEFAULT_CHESS_GAME_ID);
//then
try {
jdbcTemplateChessDao.findById(DEFAULT_CHESS_GAME_ID);
} catch (Exception e) {
}
}
}