DB연동 및 mybatis 설정이 끝났다면
junit 을 이용하여 설정이 잘 되었는지 확인을 해보자.
1. Test 코드 작성
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
|
package com.jpp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.context.junit4.SpringRunner;
import com.jpp.main.config.MybatisConfig;
import com.jpp.main.dao.MainDAO;
import com.jpp.main.vo.UserVO;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MainServiceTest {
@Autowired
private MainDAO mainDao;
@Test
public void getUserList() throws Exception {
for(UserVO vo : mainDao.getUserList()) {
System.out.println(vo.getName());
}
}
}
|
cs |
Spring Framework 에서 Bean 을 가져오기위해 @ContextConfiguration(classes = ~) 을 사용했지만
Spring Boot 는 @*Test(@SpringBootTest 를 포함한 각종 Test 어노테이션) 사용시 Bean 을 알아서 가져온다고 한다.
※JUnit 4 사용시 @RunWith(SpringRunner.class) 를 꼭 달아주어야 한다.
※ @SpringBootTest(classes = {MainDAO.class, MybatisConfig.class}) 와 같이 테스트에 사용할 특정 Bean 을 지정해 줄 수 도 있다.
※ ApplicationContext (스프링컨텍스트) 에서 DAO bean 을 .getBean으로 가져와 테스트 하는 것 또한 가능하다.
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
31
32
33
34
35
|
package com.jpp;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.SqlSessionTemplate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.ApplicationContext;
import org.springframework.test.context.junit4.SpringRunner;
import com.jpp.main.config.MybatisConfig;
import com.jpp.main.dao.MainDAO;
import com.jpp.main.vo.UserVO;
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {MainDAO.class, MybatisConfig.class})
public class MainServiceTest {
//@Autowired
//private MainDAO mainDao;
@Autowired
private ApplicationContext context;
@Test
public void getUserList() throws Exception {
MainDAO dao = context.getBean("mainDAO", MainDAO.class);
for(UserVO vo : dao.getUserList()) {
System.out.println(vo.getName());
}
}
}
|
cs |
2. Run as JUnit Test 로 실행.
결과 :
콘솔 결과 :
만약 테스트를 기존에 사용하는 DB가 아닌 별도의 DB 에서 하고자 하는 경우는 어떻게 해야할까?
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
|
package com.jpp;
import javax.sql.DataSource;
import org.apache.ibatis.session.SqlSessionFactory;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.SqlSessionTemplate;
import org.mybatis.spring.annotation.MapperScan;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Import;
import org.springframework.core.io.Resource;
import org.springframework.core.io.support.PathMatchingResourcePatternResolver;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import com.jpp.main.dao.MainDAO;
import com.jpp.main.vo.UserVO;
@RunWith(SpringRunner.class)
@SpringBootTest
public class MainServiceTest {
@Autowired
private MainDAO mainDao;
// @Autowired
// private ApplicationContext context;
@Test
public void getUserList() throws Exception {
//MainDAO dao = context.getBean("mainDAO", MainDAO.class);
for(UserVO vo : mainDao.getUserList()) {
System.out.println(vo.getName());
}
}
@TestConfiguration
@MapperScan(value= {"com.jpp.main.mapper"})
@EnableTransactionManagement
public static class TestConfig {
@Bean
public DataSource customDataSource() {
return DataSourceBuilder.create()
.url("jdbc:mysql://ip:3306/~?useSSL=false&serverTimezone=UTC")
.driverClassName("com.mysql.cj.jdbc.Driver")
.username("id")
.password("pw")
.build();
}
@Bean
public SqlSessionFactory sqlSessionFactory(DataSource dataSource)throws Exception{
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource);
Resource[] res = new PathMatchingResourcePatternResolver().getResources("classpath:mapper/*Mapper.xml");
sessionFactory.setMapperLocations(res);
return sessionFactory.getObject();
}
@Bean
public SqlSessionTemplate sqlSessionTemplate(SqlSessionFactory sqlSessionFactory) throws Exception {
return new SqlSessionTemplate(sqlSessionFactory);
}
}
}
|
cs |
위와 같이 @TestConfiguration 을 테스트 코드 내부에 inner Class로 작성하여 테스트만을 위한 DB 설정을 따로 해줄 수 있다.
테스트 코드 내부에 inner Class 로 @TestConfiguration 작성시 별다른 설정이 없어도 @SpringBootTest 가 해당 config Bean을 인식하여 DI 한다.
inner Class가 아닌 외부에 TestConfig.java 파일을 따로 작성해줄 경우 @Import(TestConfig.class) 어노테이션을 @SpringBootTest 와 함께 달아주어야 테스트 코드에서 주입 및 사용이 가능하다.
ex)
@RunWith(SpringRunner.class)
@SpringBootTest
@Import(TestConfig.class)
그럼 이제 위의 테스트 코드를 실행해 보자.
아래와 같은 에러가 발생한다.
The bean 'customDataSource', defined in com.jpp.MainServiceTest$TestConfig, could not be registered. A bean with that name has already been defined in class path resource [com/jpp/main/config/MybatisConfig.class] and overriding is disabled.
동일한 이름을 가진 Bean이 MybatisConfig.class에 이미 정의되어 있어 TestConfiguration 으로 작성한 Bean 을 등록할 수 없단다.
※ 동일한 Bean 의 이름이 존재할 경우 IoC 컨테이너가 Test 코드 내의 TestConfiguration 어노테이션이 달린 Bean 을 우선적으로 인식하여 주입해줄까 싶었는데 그것 까진 안되나보다.
27번라인을 아래와 같이 고쳐주자
@SpringBootTest(classes = {TestConfig.class, MainDAO.class})
: @SpringBootTest 어노테이션에 테스트 DB가 설정되어있는 Bean class와 이를 사용할 class 를 명시
다시 테스트 모드로 실행시켜보면 결과는 성공일 것이다.
※ Test용 Config 를 외부 클래스로 작성하고 테스트코드에서 사용하고자 할 경우
1. 앞서 언급한 @Import 를 사용하는 대신
2. @SpringBootTest(classes = {TestConfig.class}) 와 같이 테스트용 Config 를 명시하여 사용 할 수 도 있다.
(@Import 를 사용하지 않아도 주입 받아 사용이 가능)
※ 단, 위처럼 프로젝트 내에 동일한 이름의 Bean 이 존재할 경우(2개의 DataSource Bean 이 동일한 이름으로 존재) @SpringBootTest(classes = {TestConfig.class, MainDAO.class})와 같이 테스트에 사용할 Bean을 명시하여 사용해야한다. (@Import만 사용시 앞서 살펴보았던 에러와 동일하게, Bean 이 중복 선언된다는 Exception이 발생한다)
* Controller를 테스트 하는 경우 아래와 같이 가능하다.
1. 테스트 대상 코드
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
31
32
|
package com.jpp.main.controller;
import java.util.List;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.servlet.ModelAndView;
import com.jpp.main.service.MainService;
import com.jpp.main.vo.UserVO;
@Controller
public class MainController {
@Autowired
private MainService mainService;
@PostMapping("/api2")
@ResponseBody
public String api(@RequestBody String test) throws Exception {
String rs = "good";
System.out.println("api2 called !");
return "{\"good\":\"res\"}";
}
}
|
cs |
2. test class
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
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
|
package com.jpp;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.http.MediaType;
import org.springframework.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import com.jpp.main.controller.MainController;
import com.jpp.main.service.MainService;
@RunWith(SpringRunner.class)
@WebMvcTest(MainController.class)
public class MainServiceTest2 {
@Autowired
private MockMvc mvc;
@MockBean
private MainService mainService;
@Test
public void api() throws Exception {
ResultActions actions =
mvc.perform(post("/api2")
.contentType(MediaType.APPLICATION_JSON_UTF8)
.content("{\"test\":\"val\"}")
).andDo(print());
actions.andExpect(status().isOk());
}
}
|
cs |
3. junit 실행 결과
JUnit 과 관련된 트랜잭션(@Transactional) 부분, Mock 객체 등에 대한 내용은 추가 공부 및 정리 후 작성 하겠다.
Spring Boot의 Test코드에 대한 설명이 매우 잘 되어 있는 글
'back > Spring Boot' 카테고리의 다른 글
[logback] 로그파일 분기처리하기 : SIFT 사용 (0) | 2022.07.14 |
---|---|
[Spring Boot] junit 기본 사용법 (0) | 2019.12.26 |
token, jwt , oauth 2.0 (0) | 2019.12.17 |
[Spring Boot] 게시판 만들기 2 : DB 연동 및 Mybatis 설정 (0) | 2019.09.19 |
[Spring Boot] 게시판 만들기 1 : 프로젝트 생성 (0) | 2019.09.19 |