source code:  https://github.com/kgmhk/spring-boot-tutorial/tree/unit-test

1. build.gradle 파일에 testCompile 추가

buildscript {
    repositories {
        mavenCentral()
    }
    dependencies {
        classpath("org.springframework.boot:spring-boot-gradle-plugin:2.1.6.RELEASE")
    }
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'idea'
apply plugin: 'org.springframework.boot'
apply plugin: 'io.spring.dependency-management'

bootJar {
    baseName = 'helloworld'
    version =  '0.1.0'
}

repositories {
    mavenCentral()
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

dependencies {
    compile("org.springframework.boot:spring-boot-starter-web")
    testCompile("org.springframework.boot:spring-boot-starter-test")  // test complie 추가
}

 

2. test case 추가

  • "/" , "/hello" endpoint 에 대한 test case 추가
src/test/java/hello/HelloControllerTest.java
package hello;

import static org.hamcrest.Matchers.equalTo;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
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.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
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.request.MockMvcRequestBuilders;

@RunWith(SpringRunner.class)
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {

    @Autowired
    private MockMvc mvc;

    @Test
    public void indexTest() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))   // "/" 에 대한 request 요청
                .andExpect(status().isOk())                                               // response 가 200 ok 일때
                .andExpect(content().string(equalTo("Greetings from Spring Boot!")));     // response로 받은 데이터가 같은지 확인
    }

    @Test
    public void helloTest() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))   // "/hello" 에 대한 request 요청
                .andExpect(status().isOk())                                                    // response 가 200 ok 일때
                .andExpect(content().string(equalTo("Hello world")));                          // response로 받은 데이터가 같은지 확인
    }
}
  • integration test 추가
src/test/java/hello/HelloControllerIT.java
package hello;

import static org.hamcrest.Matchers.*;
import static org.junit.Assert.assertThat;

import java.net.URL;

import org.junit.Before;
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.boot.test.web.client.TestRestTemplate;
import org.springframework.boot.web.server.LocalServerPort;
import org.springframework.http.ResponseEntity;
import org.springframework.test.context.junit4.SpringRunner;

@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerIT {

    @LocalServerPort
    private int port;

    private URL base;

    @Autowired
    private TestRestTemplate template;

    @Before
    public void setUp() throws Exception {
        this.base = new URL("http://localhost:" + port + "/");
    }

    @Test
    public void indexTest() throws Exception {
        ResponseEntity<String> response = template.getForEntity(base.toString(),
                String.class);
        assertThat(response.getBody(), equalTo("Greetings from Spring Boot!"));
        
    }

    @Test
    public void helloTest() throws Exception {
        ResponseEntity<String> response = template.getForEntity(base.toString() + "hello",
                String.class);
        assertThat(response.getBody(), equalTo("Hello world"));
        
    }
}

 

3. unit test run

  • unit test 성공 시
$ gradle test

> Task :test
2019-08-01 15:28:09.933  INFO 98766 --- [       Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2019-08-01 15:28:09.933  INFO 98766 --- [       Thread-8] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
  • unit test 실패 시
$ gradle test

> Task :test

hello.HelloControllerTest > helloTest FAILED
    java.lang.AssertionError at HelloControllerTest.java:36
2019-08-01 15:30:51.739  INFO 99045 --- [       Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2019-08-01 15:30:51.739  INFO 99045 --- [       Thread-8] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

4 tests completed, 1 failed

> Task :test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///Users/gkwak/Documents/spring/helloworld/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 5s
3 actionable tasks: 2 executed, 1 up-to-date

4. ETC

  • unit test 실패 시 `gradle test --debug`나 `gradle test --info` 를 사용하면 좀더 자세한 로그를 볼 수 있다. 하지만 --bebug나 --info를 사용 시 너무 많은 로그가 출력되므로 gradle.build에 아래 testLogging 의 exceptionFormat 을 'full'로 설정하면 적절하게 볼 수 있다.
  • 아래에 예를 통해 알아보자.
  • gradle.build에  아래 항목을 추가
test {
    testLogging {
        exceptionFormat = 'full'
    }
}
  • HelloControllerTest.java 에서 테스트 항목 중 하나를 실패하도록 수정
@Test
public void helloTest() throws Exception {
	mvc.perform(MockMvcRequestBuilders.get("/hello").accept(MediaType.APPLICATION_JSON))
	.andExpect(status().isOk())                                                    
	.andExpect(content().string(equalTo("it will cause failure")));  // response는 "Hello world" 이나 테스트는 "it will cause fail" 이므로 이 테스트는 실패하게된다.
}
  • 이후 다시 unit test를 진행하면 실제 retrun 되는 response와 다른점이 아래와 같이 로그에 출력된다.
$ gradle test

> Task :test

// 아래와 같이 response와 expected가 다를 경우 해당 내용이 출력

hello.HelloControllerTest > helloTest FAILED
    java.lang.AssertionError: Response content
    Expected: "it will cause fail"
         but: was "Hello world"
        at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:20)
        at org.springframework.test.web.servlet.result.ContentResultMatchers.lambda$string$3(ContentResultMatchers.java:130)
        at org.springframework.test.web.servlet.MockMvc$1.andExpect(MockMvc.java:195)
        at hello.HelloControllerTest.helloTest(HelloControllerTest.java:36)
2019-08-01 15:39:04.475  INFO 99780 --- [       Thread-8] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'
2019-08-01 15:39:04.475  INFO 99780 --- [       Thread-5] o.s.s.concurrent.ThreadPoolTaskExecutor  : Shutting down ExecutorService 'applicationTaskExecutor'

4 tests completed, 1 failed

> Task :test FAILED

FAILURE: Build failed with an exception.

* What went wrong:
Execution failed for task ':test'.
> There were failing tests. See the report at: file:///Users/gkwak/Documents/spring/helloworld/build/reports/tests/test/index.html

* Try:
Run with --stacktrace option to get the stack trace. Run with --info or --debug option to get more log output. Run with --scan to get full insights.

* Get more help at https://help.gradle.org

BUILD FAILED in 4s
3 actionable tasks: 2 executed, 1 up-to-date

 

Posted by 사용자 guru_k

댓글을 달아 주세요