오 롬복 대박 신기함 자동생성을 자동생성해주는ㅋㅋㅋ TDD는 맨 뒷 단계인 QA-배포만 경험해보다가 기능 단위로 테스트해보면서 개발하는 과정을 작게나마 적용해보니 필요성이 더 와닿았달까.. 내가 만들면 내가 만든대로 테스트를 하게 되는 경향이 있는데, 테스트 코드를 통한 사전 테스트가 확신을 높여주는 도구로 사용되기 좋을 것 같음
JUnit
, spring-test
src/test/java > 패키지 > test 클래스 생성되어 있음
연관 있는 테스트끼리 같은 클래스에 테스팅 코드 작성(필요 시 클래스 추가)
@SpringBootTest
@Test
package com.jw.spring12;
import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;
//이 표시를 하면 프로젝트 내의 등록된 Spring 도구를 사용할 수 있음
@SpringBootTest
class Spring12testApplicationTests {
@Test //이 표시가 붙은 메소드는 테스트용 메소드
void contextLoads() {
System.out.println("Test code");
}
}
클래스명을 Test라고 지으면 Test 어노테이션 때문에 에러 발생함
메소드 생성 시 주의사항
가설이 있어야 함
@SpringBootTest
public class Test01 {
@Test
public void basic01() {
//목표: 1.1 + 2.2는 3.3인가?
double a = 1.1;
double b = 2.2;
double c = a + b;
double d = 3.3;
System.out.println(c==d); //false
}
assertEquals()
, assertNotEquals()
사용//단정문(Assertion)
//-> 목표: 1.1 + 2.2는 3.3일 것이다
assertEquals(c, d);
//목표가 부정문이라면 assertNotEquals()사용
TDD를 적용해 포켓몬스터 등록 기능을 구현하는 과정을 정리하고자 함. 컨트롤러와 DTO, DAO 등을 먼저 구현하고 브라우저에서 직접 기능 동작 여부를 확인했던 것과 달리, 단위 테스트와 모듈 테스트 등을 거치면서 필요한 내용들을 구현할 예정임
[진행 순서]
1. 포켓몬스터 데이터 등록을 위한 insert 쿼리 작성
2. 해당 쿼리를 통해 테이블에 데이터가 등록되는지 단위 테스트 진행
3. DAO 생성 후 주입 테스트
4. DAO, DaoImpl에 insert 기능 모듈화
5. Dao.insert()를 통해 테이블에 데이터가 등록되는지 모듈 테스트 진행
6. 컨트롤러 생성
7. 매핑 테스트
기본적으로는 클래스와 DAO 만들어서 주입해야 불러올 수 있는 도구를 바로 사용할 수 있음. 스프링에서 제공하는 도구는 바로 주입할 수 있음
테스트를 위한 사전/사후 작업 등이 필요할 때, 하나의 메소드에서 여러 작업을 하지 않고 분리
@BeforeEach
@Test
: 테스트 코드@AfterEach
: 정리 작업@SpringBootTest
public class Test04 {
@BeforeEach //준비 작업
public void before() {
System.out.println("데이터 추가");
}
@Test //테스트
public void test() {
System.out.println("조회 테스트");
}
@AfterEach //테스트 후 정리 작업
public void after() {
System.out.println("데이터 삭제");
}
}
INSERT 쿼리를 먼저 테스트하고 성공 시, DAO를 주입해 insert 기능 테스트
src/main에 있는 DAO를 src/test에 불러올 수 있음
jdbctemplate 주입 테스트 → 성공(pocketmonster 테이블에 (56,팬텀,환영) 데이터가 등록된 것 확인) → DaoImpl에 대한 확신을 가질 수 있음
@SpringBootTest
public class Test02 {
@Autowired
private JdbcTemplate jdbcTemplate;
@Test
public void basic02() {
int no = 56;
String name = "팬텀";
String type = "환영";
String sql = "insert into pocket_monster"
+ "(no, name, type) values(?, ?, ?)";
Object[] param = {no, name, type};
jdbcTemplate.update(sql, param);
}
}
@SpringBootTest
public class Test03 {
@Autowired
private PocketMonsterDao pocketMonsterDao;
@Test
public void test01() {
//System.out.println(pocketMonsterDao);
assertNotNull(pocketMonsterDao);
}
@Test
public void test02() {
pocketMonsterDao.insert(60, "발챙이", "물");
}
}
테스트는 서버가 꺼져 있어도 가능하다고 위에서 언급함. 컨트롤러는 요청을 받아야 하는데 서버가 꺼져 있다면, 임시로 켜서 테스트하고 다시 꺼지게 하면 됨. 가짜 요청 생성 도구를 만들어서 테스트하는 방법을 사용함
WebApplicationContext
standaloneSetup
private MockMvc mockMvc;
@Autowired
private WebApplicationContext ctx;
@BeforeEach
public void before() {
mockMvc = MockMvcBuilders.webAppContextSetup(ctx).build();
}
자바는 객체를 통해서 메소드를 불러야 하는데, 테스트 한정 스테틱 메소드를 통해서 불러올 수 있음
.perform()
: 요청을 수행하고 추가 조치를 수행할 수 있는 ResultActions 데이터 반환.andDo()
: 수행할 일반적인 행동을 설정.andExpect()
: 성공 상황을 설정(단정).andReturn()
: 결과에 대한 정보들을 MvcResult 형태로 반환@Test
public void test() throws Exception {
//assertNotNull(ctx);
mockMvc.perform(get("/pocketmon/insert"))
.andExpect(status().is(200)) //네트워크 상태 200: 정상
.andDo(print())
.andReturn();
}
@AutoConfigureMockMvc
: MockMvc에 대한 자동 설정@SpringBootTest
@AutoConfigureMockMvc //MockMvc에 대한 자동 설정
public class Test05 {
@Autowired
private MockMvc mockMvc;
}
<br>
### POST 매핑 테스트
```java
@Test
public void pocketMonsterInsertTest() throws Exception {
mockMvc.perform(post("/pocketmon/insert"))
.andExpect(status().is3xxRedirection())
.andDo(print())
.andReturn();
}
이대로 실행하면 전달하는 데이터가 없기 때문에 실패함. 요청 명령은 perform 뿐이므로 여기에 데이터를 첨부해야 함(post 주소 + param)
포켓몬스터 번호(no)의 자료형은 int인데, String으로 첨부해야 함.
http는 원래 파라미터에 String
만 허용
패킷 크기
와 관련이 있음. 패킷 크기는 1byte인데, 이를 넘으면 반드시 분해와 조립 과정이 생김. (int: 4byte) 자바는 유일하게 문자열이 패킷 단위 크기에 맞음UTF-8
로 사용 중이므로 조립과 분해에 대해 따로 신경쓰지 않아도 됨(* UTF-8: 한글을 초/중/종성으로 나눔)@Test
public void pocketMonsterInsertTest() throws Exception {
mockMvc.perform(
post("/pocketmon/insert")
.param("no", "77")
.param("name", "디그다")
.param("type", "풀")
)
.andExpect(status().is3xxRedirection())
.andDo(print())
.andReturn();
}
방법1. Spring Boot Add Starters에서 추가
방법2. Maven Central Repository에서 추가
프로젝트에만 추가하면 import나 annotation 등은 사용할 수 있지만 실제로 에디터에서 인지하지 못하기 때문에 오류가 발생함
Lombok은 멤버 필드만 존재한다면 나머지 구성 요소들을 Annotation으로 만들도록 지원해줌
@ToString(exclude = “score”)
@Data
@NoArgsConstructor
public class StudentDto {
private String name;
private int score;
}
StudentDto studentDto = StudentDto.builder().build();
Student a = Student.builder().name("피카츄").score(50).build();
[참고]