'@AutoConfigureMockMvc'에 해당되는 글 1건

  1. 2019.10.10 :: Springboot - Springboot MVC Test(JUnit)
Web/Spring 2019. 10. 10. 00:22

 

오늘 포스팅할 내용은 간단하게 Springboot Test이다. 아주 자세하게 다루어보진 않지만, 유용하고 자주 사용하는 부분이다. 간단하게 유닛테스트하는 내용은 이전 포스팅을 참고하고, 이번 내용은 Springboot 환경에서의 테스트 내용을 다룰것이다.

 

TDD - 테스트 주도 개발(Test Driven Development)

작성하려는 코드가 있다면 항상 먼저 어떻게 그 코드를 테스트할지 고민해야한다. 코드를 작성한 후에 어떻게 테스트할지 고민하기보다 작성할 코드를 묘사하는 테스트를 설계해야 한다. 이것이 테스트 주도 개발..

coding-start.tistory.com

 

다음 코드는 Springboot에서 빈으로 등록된 객체들을 사용할수 있게하는 테스트이다. 즉, ApplicationContext를 띄우는 것이다.

 

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
============application.properties============
test.property=test-property
==============================================
@Service
public class CommonService {
    @Autowired
    private CommonBean commonBean;
 
    public String print(){
        String result = commonBean.print();
        System.out.println(result);
        return result;
    }
}
@Component
public class CommonBean {
    @Value("${test.property}")
    private String testProperty;
    public String print(){
        System.out.println(testProperty);
        return testProperty;
    }
}
 
@RunWith(SpringRunner.class)
@SpringBootTest
public class TestPropertyTest {
    @MockBean
    private CommonBean commonBean;
    @Autowired
    private CommonService commonService;
    @Test
    public void print(){
        commonBean.print();
    }
}
 
cs

 

위 테스트는 성공적으로 통과할 것이다. 하지만 여기서 하나 문제점이 존재한다. 만약 아주 큰 애플리케이션이라 ApplicationContext 로드에 아주 긴 시간이 걸린다면 작은 테스트를 하나 수행할때마다, 긴 시간이 걸릴 것이다. 이러할때, 우리가 테스트에 필요한 빈만 띄울수 있다. 아래 코드를 확인하자.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {
        CommonService.class,
        CommonBean.class
},initializers = ConfigFileApplicationContextInitializer.class)
public class TestPropertyTest {
 
    @Autowired
    private CommonService commonService;
 
    @Test
    public void print(){
        commonService.print();
    }
 
}
cs

 

2가지 방법이 존재한다. 첫번째 방법은 @ContextConfiguration 어노테이션을 이용하는 방법이다. 인자로 빈으로 띄울 클래스를 넘긴다. 여기서 중요한것을 관련된 클래스도 모두 넣어줘야한다는 것이다. 위를 예를 들면 CommonService 클래스를 빈으로 등록할 것인데, 해당 클래스의 내용을 보면 CommonBean을 DI받고 있으므로, CommonBean도 빈으로 띄워줘야하는 것이다. 나중에 다루어볼 것이지만 위와같이 빈으로 띄울 클래스를 명시적으로 등록해도되지만, 굳이 테스트에 사용하지 않으면 Mock 빈으로 등록해주어도 된다. 두번째 인자는 initializers이다. 만약 이 인자가 없다면, CommonBean에서 @Value로 DI 받고있는 프로퍼티값을 주입받지 못한다. 즉, application.properties의 내용을 읽지 못하는 것이다. 내부적으로 @Value를 받기위한 빈이 뜨지 못해서 그런 것 같다. 이와 같은 문제를 해결하기 위해서 initializers = ConfigFileApplicationContextInitializer.class를 등록해주므로써 프로퍼티값을 읽어 올 수 있게 하였다. 

 

두번째 방법은 아래와 같다. @SpringBootTest를 이용하여 더 간단한 설정으로 SpringBoot Test를 위한 설정을 할 수 있게된다. 또한 테스트에만 사용할 프로퍼티를 정의할 수도 있다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
@RunWith(SpringRunner.class)
@SpringBootTest(classes = {CommonBean.class,CommonService.class}
,properties = {"test.property=dev-property"})
public class TestPropertyTest {
 
    @Autowired
    private CommonService commonService;
 
    @Test
    public void print(){
        commonService.print();
    }
 
}
cs

 

두번째는 Mock빈을 이용하는 방법이다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@RunWith(SpringRunner.class)
@ContextConfiguration(classes = {
        CommonService.class
},initializers = ConfigFileApplicationContextInitializer.class)
public class TestPropertyTest {
 
    @MockBean
    private CommonBean commonBean;
    @Autowired
    private CommonService commonService;
 
    @Test
    public void mockBeanTest(){
        given(commonBean.print()).willReturn("Test Result");
        commonService.print();
    }
 
}
cs

 

CommonService의 비즈니스 로직을 테스트하고 싶은데, 굳이 CommonBean은 띄울 필요가 없을때, 위와 같이 MockBean을 등록해서 임의로 Mock 빈이 리턴할 값을 명시할 수 있다. 위 소스는 CommonService만 테스트를 위한 빈으로 띄우는데, 내부적으로 관련있는 CommonBean은 띄우지 않고 Mock 빈으로 띄운다. 그리고 CommonBean이 리턴하는 값을 임의로 "Test Result"라는 값으로 지정해주었다. 이렇게 테스트할 빈만 집중하여 테스트가 가능해지며 사이드 코드의 양을 줄일 수 있게 된다.

 

다음은 간단하게 Controller를 테스트할 수 있는 코드이다. 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
RunWith(SpringRunner.class)
@WebMvcTest(controllers = CommonTestController.class)
@ContextConfiguration(classes = {
        CommonTestController.class,
        CommonBean.class,
        CommonService.class}
        ,initializers = ConfigFileApplicationContextInitializer.class)
public class TestControllerTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void resultTest() throws Exception {
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/test/common")).andReturn();
        System.out.println(result.getResponse().getContentAsString());
    }
 
}
cs

 

굳이 스프링을 실행시키지 않고도 컨트롤러를 테스트할 수 있다. @WebMvcTest 어노테이션을 이용하여 스프링 컨트롤러 테스트가 가능한 설정을 띄워준다. 즉, MVC관련 빈만 띄워 더욱 가볍게 스프링 컨트롤러 테스트가 가능하다. 위와 같은 어노테이션도 가능하며 아래와 같은 어노테이션 설정도 사용가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = {
        CommonTestController.class,
        CommonBean.class,
        CommonService.class
})
public class TestControllerTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void resultTest() throws Exception {
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/test/common")).andReturn();
        System.out.println(result.getResponse().getContentAsString());
    }
 
}
cs

 

@AutoConfigureMockMvc 어노테이션을 이용하여 MVC 테스트를 위한 설정을 AutoConfiguration하게 할수 있다. 물론, MVC테스트를 위하여 내부적으로 내/외부 연동코드가 있다면 내/외부연동을 하지 않기 위해 Mock 빈등을 이용하여 테스트 가능하다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = {
        CommonTestController.class
})
public class TestControllerTest {
 
    @Autowired
    private MockMvc mockMvc;
    @MockBean
    private CommonBean commonBean;
    @MockBean
    private CommonService commonService;
 
    @Test
    public void resultTest() throws Exception {
        given(commonBean.print()).willReturn("test");
        given(commonService.print()).willReturn("test");
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/test/common")).andReturn();
        System.out.println(result.getResponse().getContentAsString());
    }
 
}
cs

 

마지막으로 테스트만을 위한 application.properties를 사용는 방법이다. 우선, application-test.properties를 classpath 밑의 resources 폴더 안에 넣어준다.(기존 application.properties 경로와 동일) 그리고 아래와 같이 @ActiveProfile 어노테이션을 이용하여 프로파일을 이용하여 읽어올 프로퍼티파일을 명시한다.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
@RunWith(SpringRunner.class)
@AutoConfigureMockMvc
@SpringBootTest(classes = {
        CommonTestController.class,
        CommonBean.class,
        CommonService.class
})
@ActiveProfiles("test")
public class TestControllerTest {
 
    @Autowired
    private MockMvc mockMvc;
 
    @Test
    public void resultTest() throws Exception {
        MvcResult result = mockMvc.perform(MockMvcRequestBuilders.get("/test/common")).andReturn();
        System.out.println(result.getResponse().getContentAsString());
    }
 
}
cs

 

위 코드는 기존 application.properties가 아닌, application-test.properties 파일을 읽어 컨텍스트를 구성할 것이다.

 

아주 간단하게만 springboot test를 다루어봤는데, 추후 포스팅에서 지금까지 다룬 내용과 더 자세한 테스팅관련 기술을 다루어볼 것이다.

posted by 여성게
: