목차
junit을 잘 활용하면 브라우저에 접속하지 않아도 테스트를 할 수 있다.
Library 설정
Junit Library추가
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
spring-test Library추가
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<!-- 버전은 spring버전과 맞추기 -->
<version>5.2.25.RELEASE</version>
<scope>test</scope>
</dependency>
테스트 파일 생성 및 실행
테스트 파일 생성
src/test/java에 테스트파일을 생성한다
클래스명으로 Test라는 이름을 쓰면 안된다
Junit의 anootation명이 Test이기 때문에 에러가 난다!
import org.junit.Test;
public class tempTest {
@Test
public void test() {
System.out.println("실행하고자 하는 테스트메소드 작성");
}
}
테스트 메소드 실행
여러개의 테스트 메소드 중 한 메소드만 실행하고 싶을 경우 해당 메소드의 이름을 더블클릭 후 위 방법으로 메소드를 실행하면 해당 메소드만 실행된다.
테스트 결과 확인
Assertion
테스트의 성공과 실패를 검증한다.
내가 예상한 값을 먼저 기입한 후, 결과가 내가 예상한 값과 다르게 나오면 테스트가 실패한 것으로 간주한다.
- assertEquals(a, b)
- assertTrue(a)
- assertFalse(a)
- assertNull(a)
- assertNotNull(a)
- 등 수 많은 asertXXX()메소드가 있으니 ctrl + space로 원하는 기능을 찾아서 사용하면 된다.
public class tempTest {
@Test
public void test() {
int a = 5;
assertEquals(3, a);
}
}
위 코드를 수행할 경우, 실행은 잘 되지만 예상했던 값(3)이 a값(5)와 다르기 때문에 테스트 실패로 처리된다.
Junit의 실행 순서
BeforeClass → Before → Test → After → AfterClass
@Before @After
Before Annotation이 달린 메소드는 다른 테스트 메소드들이 실행되기 전에 실행된다.
After Annotation이 달린 메소드는 다른 테스트 메소드들이 실행된 후에 실행된다.
public class tempTest {
@Before
public void before() {
System.out.println("before");
}
@After
public void after() {
System.out.println("after");
}
@Test
public void test() {
System.out.println("테스트");
}
@Test
public void test2() {
System.out.println("테스트2");
}
}
실행 결과
@BeforeClass @AfterClass
BeforeClass Annotation이 달린 메소드는 처음 한 번만 수행된다.
AfterClass Annotation이 달린 메소드는 마지막 한 번만 수행된다.
이 둘은 반드시 static으로 선언되어야 한다.
package test;
import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;
public class tempTest {
@BeforeClass
public static void before() {
System.out.println("처음 한번만");
}
@AfterClass
public static void after() {
System.out.println("마지막 한번만");
}
@Test
public void test() {
System.out.println("테스트");
}
@Test
public void test2() {
System.out.println("테스트2");
}
}
Web 없이 SQL 테스트하기
일반적으로 SQL을 실행하는데 까지 필요한 과정
VO만들기 → Mapper만들기 → Mapper Interface만들기 → Service만들기 → Controller만들기 → 웹페이지 만들기 → 웹에서 실행
Junit을 사용해 SQL을 실행하는데 까지 필요한 과정
VO만들기 → Mapper만들기 → Mapper Interface만들기 → Test파일 만들기 → 테스트 실행
Junit을 사용하면 간단히 테스트를 수행할 수 있다.
이때 아래 세 @Annotation을 꼭 작성해야 한다.
- @RunWith
- @ContextConfiguration
- java : @ContextConfiguration(classes = 클래스경로)
- xml : @ContextConfiguration(location = 클래스경로)
- @WebAppConfiguration
Mapper Interface Test
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { sinhanDS.first.project.config.MvcConfig.class })
@WebAppConfiguration
public class MapperInterfaceTest {
@Autowired
ProductMapper mapper; //테스트 할 mapper 주입
@Test
public void test() {
List<ProductVO> list = mapper.product_list();
for(int i = 0; i < list.size(); i++) {
System.out.println(list.get(i));
}
}
}
실행 SQL문 SELECT * FROM product
Service Test
@Autowired
SellerService service; //테스트할 서비스 빈 주입
@Test
public void test2() {
System.out.println(service.getProduct(4));
}
실행 SQL문 SELECT * FROM product WHERE no=4
Controller Test
JSP가 없어도 Controller를 테스트 할 수 있다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { sinhanDS.first.project.config.MvcConfig.class })
@WebAppConfiguration
public class tempTest {
/* 테스트 환경에서 실행할 때 주소를 입력하기 위해 사용 */
@Autowired
WebApplicationContext ctx;
/* 테스트 환경에서 실행할 가상의 MVC */
MockMvc mock;
/* 테스트 함수를 수행하기 전에 @Before 함수로 mok을 생성해야 한다 */
@Before
public void before() {
mock = MockMvcBuilders.webAppContextSetup(ctx).build();
}
/* 테스트 해볼 메소드를 만든다. */
@Test
public void regist_product() throws Exception {
RequestBuilder req = MockMvcRequestBuilders.get("/seller/idCheck.do")
.param("id", "collagom") //parameter가 필요할 경우 parameter 부여
.param("ohterParam", "insertHere");//여러 개의 parameter를 부여할 수 있다
mock.perform(req);
}
}
통합테스트 수행하기
준비 작업으로 Test1, Test2 생성
통합 테스트 수행을 위한 Java파일 생성
@RunWith(Suite.class)
@SuiteClasses({Test1.class, Test2.class})
public class IntergratedTest {
}
- 아래 Annotation을 작성
- @RunWith(Suite.class)
- @SuiteClasses({통합 테스트 수행을 위한 클래스들을 나열})
위 자바파일을 Run as Junit Test로 작동시키면 Test1.java, Test2.java 파일 내의 모든 Test메소드를 실행한다.
실행 결과
통합 테스트 수행 중 에러가 날 경우
위와 같이 어느 부분에서 에러가 났는지 체크해준다.
Test할 때 Interceptor 통과하기
Interceptor에 의한 Block
Interceptor에 대한 글은 아래 글에 작성으니 참고해보자!
https://cider-glass.tistory.com/19
로그인을 해야만 /seller/index.do로 접속할 수 있도록 Interceptor를 설정해줬다.
때문에 아래 코드를 실행하면 인터셉터에 의해 막힌다.
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { sinhanDS.first.project.config.MvcConfig.class })
@WebAppConfiguration
public class InterceptorTest {
@Autowired
WebApplicationContext ctx;
MockMvc mock;
@Before
public void before() {
mock = MockMvcBuilders.webAppContextSetup(ctx).build();
}
@Test
public void interceptorTest() throws Exception {
RequestBuilder req = MockMvcRequestBuilders.get("/seller/index.do");
mock.perform(req);
}
}
실행결과
이 프로그램의 Interceptor는 다음과 같다.
public class SellerLoginInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
HttpSession sess = request.getSession();
SellerVO login = (SellerVO)sess.getAttribute("sellerLoginInfo");
if (login == null) {
System.out.println("인터셉터 컷");
return false;
}
System.out.println("인터셉터 통과");
return true;
}
}
이 프로그램의 Interceptor는 Session에서 로그인여부를 받아와서 검사하는 구조이기 때문에 Session에 로그인 정보를 저장해서 테스트를 수행할 필요가 있다.
Test시 Session 추가하기
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = { sinhanDS.first.project.config.MvcConfig.class })
@WebAppConfiguration
public class InterceptorTest {
@Autowired
WebApplicationContext ctx;
MockMvc mock;
@Before
public void before() {
mock = MockMvcBuilders.webAppContextSetup(ctx).build();
}
@Test
public void interceptorTest() throws Exception {
RequestBuilder req = MockMvcRequestBuilders.get("/seller/index.do")
.sessionAttr("sellerLoginInfo", new SellerVO());
/* 위와 같이 sessionAttr로 Test시 사용할 Session을 설정할 수 있다!! */
mock.perform(req);
}
}
위 코드와 같이 .sessionAttr()메소드를 사용해서 Test시 사용할 Session을 설정해 줄 수 있다!
실행결과
Interceptor를 사용할 수 없는 ParameterType에 대하여
이 부분에 대해서는 사용할 수 없는지 확실치 않다. 이후에 사용 가능한 방법을 찾을 경우 수정하겠다.
@RequestParam MultipartFile
@PostMapping("/regist.do")
public String regist(@RequestParam MultipartFile filename, HttpServletRequest request, ProductVO vo, ProductCategoryVO cvo, ProductOptionVO ovo) {
System.out.println("voTest: " + vo);
if(filename != null) {
vo = service.upload_file(filename, vo);
}
service.regist(vo, cvo, ovo);
return "redirect:/seller/index.do";
}
위 코드는 JSP로부터 받아온 파일을 업로드하는 코드이다.
이때 인자로 MultipartFile을 받아오는 것을 확인할 수 있다.
위 코드를 아래 코드로 테스트하면 테스트가 동작하지 않는다.
@Test
public void regist_product() throws Exception {
RequestBuilder req = MockMvcRequestBuilders.post("/seller/product/regist.do")
.sessionAttr("sellerLoginInfo", new SellerVO())
.param("seller_no", "1").param("name", "테스트로만든상품")
.param("price", "10001").param("stock", "50")
.param("discount", "0");
mock.perform(req);
}
실행 결과처럼 인터셉터만 통과하고 voTest가 출력되지 않는다.
이는 /seller/product/regist.do 요청을 통해 인터셉터로 그 요청이 들어가기는 했지만, 인터셉터를 통과한 이후에 /seller/product/regist.do가 맵핑된 메소드로는 도달하지 못했다는 의미이다.
이때 /seller/product/regist.do 요청이 맵핑된 메소드를 아래와 같이 MultipartFile이 포함되지 않게 수정하면 테스트 코드가 잘 작동하는 것을 확인할 수 있다.
@PostMapping("/regist_forTest.do")
public String regist(HttpServletRequest request, ProductVO vo, ProductCategoryVO cvo, ProductOptionVO ovo) {
service.regist(vo, cvo, ovo);
return "redirect:/seller/index.do";
}
MultipartFile메소드를 Junit의 RequestBuilder를 넘겨주지 못했고, 이로 인해서 /seller/product/regist.do와 맵핑된 메소드와 인자의 타입이 달라서 해당 메소드를 실행하지 못한 것으로 보여진다.
RequestBuilder에 MultipartFile을 인자로 줄 수 있는 방법을 찾으면 글을 수정해보자!
'컴퓨터공학 > 스프링' 카테고리의 다른 글
Spring의 처리 흐름 (0) | 2023.12.11 |
---|---|
DB 접속정보 git에 공유되지 않도록 설정하기 (0) | 2023.12.10 |
[Slf4j] 스프링의 디버깅 도구 Slf4j Library (1) | 2023.12.10 |
[log4j.xml] 스프링의 디버깅 로그 자세히 띄우기 (1) | 2023.12.10 |
Interceptor (0) | 2023.12.05 |