Framework/Spring Boot
[Framework] Spring Boot [TDD] 테스트 코드 작성
SeungyubLee
2022. 11. 30. 14:15
TDD(Test Driven Development)란?
테스트 코드를 만들고, 이를 통과하는 최소한의 코드로 시작하여
점진적으로 개선, 확장해가는 개발 방식을 말한다.
Article 서비스를 검증하는 테스트 코드를 작성해보자
Article 서비스에서 테스트를 원하는 메소드명 우클릭 Generate > Test를 클릭하고
열린 창 하단에 테스트를 할 메소드명을 체크 후 OK를 클릭한다.
ArticleServiceTest라는 클래스 파일이 만들어지고
이 파일의 경로는 src > test > java > com.example.firstproject > service가 된다.
H2 DB를 사용하고 있었기 때문에 data.sql을 참고해 테스트 코드를 작성한다.
예상 시나리오 작성 -> 실제 결과와 비교하여 검증
<data.sql>
INSERT INTO ARTICLE(ID, TITLE, CONTENT) VALUES (2, 'AAAA', '1111');
INSERT INTO ARTICLE(ID, TITLE, CONTENT) VALUES (3, 'BBBB', '2222');
INSERT INTO ARTICLE(ID, TITLE, CONTENT) VALUES (4, 'CCCC', '3333');
<ArticleServiceTest>
package com.example.firstproject.service;
import com.example.firstproject.dto.ArticleDto;
import com.example.firstproject.entity.Article;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import static org.junit.jupiter.api.Assertions.*;
@SpringBootTest // 해당 클래스는 스프링부트와 연동되어 테스팅된다.
class ArticleServiceTest {
@Autowired ArticleService articleService;
@Test
void readAll() {
// 예상
Article a = new Article(2L, "AAAA", "1111");
Article b = new Article(3L, "BBBB", "2222");
Article c = new Article(4L, "CCCC", "3333");
List<Article> expectedList = new ArrayList<Article>(Arrays.asList(a, b, c));
// 실제
List<Article> articleList = articleService.readAll();
// 비교
assertEquals(expectedList.toString(), articleList.toString());
}
@Test
void read_success() { // read 메소드 성공 테스트
// 예상
Long id = 2L;
Article expected = new Article(id, "AAAA", "1111");
// 실제
Article article = articleService.read(id);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
void read_fail() { // read 메소드 실패 테스트 // 존재하지 않는 id를 입력한 경우
// 예상
Long id = -1L;
Article expected = null;
// 실제
Article article = articleService.read(id); // return articleRepository.findById(id).orElse(null); 이렇게 작성되어 있으므로 null 값을 갖는 expected로 비교
// 비교
assertEquals(expected, article); // null은 toString 메소드를 호출할 수 없음
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void create_success() { // create 메소드 성공 테스트 // title과 content만 있는 dto 입력
// 예상
String title = "DDDD";
String content = "4444";
ArticleDto dto = new ArticleDto(null, title, content);
Article expected = new Article(1L, title, content);
// 실제
Article article = articleService.create(dto);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void create_fail() { // create 메소드 실패 테스트 // id가 포함된 dto 입력
// 예상
String title = "DDDD";
String content = "4444";
ArticleDto dto = new ArticleDto(2L, title, content);
Article expected = null;
// 실제
Article article = articleService.create(dto); // id가 존재하는 경우 null return하도록 작성되어 있음
// 비교
assertEquals(expected, article);
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_success_1() { // update 메소드 성공 테스트 케이스 1 // 존재하는 id와 변경할 title, content만 있는 dto 입력
// 예상
Long id = 2L; // 대상 id
String title = "AAAAAAAA"; // 변경할 title
String content = "11111111"; // 변경할 content
ArticleDto dto = new ArticleDto(null, title, content);
Article expected = new Article(id, "AAAAAAAA", "11111111");
// 실제
Article article = articleService.update(id, dto);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_success_2() { // update 메소드 성공 테스트 케이스 2 작성해보기
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_fail_1() { // update 메소드 실패 테스트 케이스 1 // 존재하지 않는 id와 변경할 title, content만 있는 dto 입력
// 예상
Long id = -1L; // 대상 id
String title = "AAAAAAAA"; // 변경할 title
String content = "11111111"; // 변경할 content
ArticleDto dto = new ArticleDto(null, title, content);
Article expected = null;
// 실제
Article article = articleService.update(id, dto); // id에 해당하는 엔티티가 없는 경우 null return하도록 작성되어 있음
// 비교
assertEquals(expected, article);
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void update_fail_2() { // update 메소드 실패 테스트 케이스 2 작성해보기
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void delete_success_1() { // delete 메소드 성공 테스트 케이스 1 // 존재하는 id 입력
// 예상
Long id = 2L;
Article expected = new Article(id, "AAAA", "1111");
// 실제
Article article = articleService.delete(id);
// 비교
assertEquals(expected.toString(), article.toString());
}
@Test
@Transactional // 조회가 아닌 생성, 변경, 삭제의 경우 Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다.
void delete_fail_1() { // delete 메소드 실패 테스트 케이스 1 // 존재하지 않는 id 입력
// 예상
Long id = -1L;
Article expected = null;
// 실제
Article article = articleService.delete(id);
// 비교
assertEquals(expected, article);
}
}
테스트 코드 작성 후 메소드 옆 재생 버튼 클릭 > Run ArticleServiceTest 클릭하면 해당 메소드의 테스트가 시작된다.
화면 좌측 하단 Show Passed, Show Ignored를 선택하고
메소드명 옆에 녹색 체크(테스트 정상) 또는 X 표시(테스트 실패)를 확인한다.
모든 메소드에 대해 테스트를 진행하고자 한다면 클래스명 옆에 있는 재생 버튼을 클릭하면 된다.
조회가 아닌 생성, 변경, 삭제 테스트의 경우
Transaction으로 묶어서 Rollback할 수 있게 처리해줘야 한다. (어노테이션 추가 @Transactional)