2023. 12. 30. 12:56ㆍ- 서버/springboot
견고한 서비스를 만들고 싶은 개발자나 팀에선 TDD (Test - driven development) 를 하거나 최소한 테스트 코드는 꼭 작성했었습니다. 또한 요즘 대부분의 서비스 회사가 테스트 코드에 관해 요구 하고 있습니다.
그만큼 요즘 선망하는 서비스 회사에 취업과 이직을 하기 위해서는 테스트 코드는 절대 빠질 수 없는 요소 입니다.
먼저 한가지 짚고 갈것은 TDD와 단위테스트(unit test) 는 다른 것입니다.
TDD는 테스트가 주도하는 개발을 이야기 합니다.
단위테스트는 TDD의 첫번째 단계인 기능 단위의 테스트 코드를 작성하는 것을 이야기 합니다.
단위테스트는 TDD와 달리 테스트 코드를 꼭 먼저 작성해야 하는것도 아니고, 리팩토링도 포함되지 않습니다.
이번 포스트에서는 TDD가 아닌 단위 테스트코드 작성의 기본을 배워보겠습니다.
단위테스트 코드 없이 개발을 할 경우가 아래와 같다고 해봅시다.
1. 코드를 작성하고
2. 프로그램(Tomcat)을 실행 한뒤
3. Postman과 같은 API 테스트 도구로 Http
4. 요청하고요청 결과를 System.out.println() 으로 눈으로 검증합니다
5. 결과가 다르면 다시 프로그램(Tomcat)을 중지 하고 코드를 수정합니다
여기서 2 ~ 5는 매번 코드를 수정할 때마다 반복해야만 합니다.
톰캣을 재시작 하는 시간은 수십초에서 1분 이상 소요됩니다. 하지만 테스트코드를 작성하면 이런 문제가 해결되므로 굳이 손으로 직접 톰캣을 계속 올렸다가 내렸다 할 필요가 없습니다.
다음 문제로는 System.out.println()을 통해 눈으로 검증해야 하는 문제 입니다.
테스트코드를 작성하면 더는 사람이 눈으로 검증하지 않게 자동검증이 가능합니다. 작성된 단위 테스트를 실행만 하면 더는 수동검증은 필요 없게 되는 것입니다.
또한 개발자가 만든 기능을 안전하게 보호해 줍니다. 예를 들어 B라는 기능이 추가되어 테스트 합니다. B 기능이 잘되어 오픈 했더니 기존에 잘되던 A 기능에 문제가 생긴 것을 발견합니다. 이런 문제는 규모가 큰 서비스에서는 빈번하게 발생하는 일입니다. 하나의 기능을 추가할 때마다 너무나 많은 자원이 들기 때문에 서비스의 모든 기능을 테스트 할 수는 없습니다.
이렇게 새로운 기능이 추가 될때, 기존 기능이 잘 작동되는 것을 보장해 주는 것이 테스트 코드 입니다. A라는 기본기능을 비롯해 여러 경우를 모두 테스트 코드로 구현해 놓았다면 테스트 코드를 수행만 하면 문제를 조기에 찾을 수 있습니다.
가장 대중적인 테스트 프레임워크로는 xUnit 이 있는데 이는 개발환경에 따라 Unit테스트를 도와주는 도구라고 생각하면 됩니다. 대표적인 xUnit 프레임워크들은 다음과 같습니다.
JUnit - Java
DBUnit - DB
CppUnit - C++
NUnit - .net
이중에서 자바용인 JUnit 을 앞으로 사용하겠습니다. JUnit4 버전으로 테스트 코드를 작성합니다.
코드작성
인텔리제이에 아래와 같은 코드를 작성합니다.
Application.class
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
메인 클래스가 되는 코드 입니다.
@SpringBootApplication 으로 인해 스프링 부트의 자동설정, 스프링 Bean 읽기와 생성을 모두 자동으로 설정 됩니다.
특히나 @SpringBootApplication 이 있는 위치부터 설정을 읽어가기 때문에 이 클래스는 항상 프로젝트의 최상단에 위치 해야만 합니다.
main 메소드에서 실행하는 SpringApplication.run 으로 인해 내장 WAS (Web Application Server)를 실행합니다. 내장 WAS란 별도로 외부에 WAS를 두지 않고 애플리케이션을 실행할때 내부에서 WAS를 실행하는 것을 의미 합니다. 이렇게 되면 항상 서버에 톰캣을 설치할 필요가 없고, 스프링 부트로 만들어진 Jar파일로 실행하면 됩니다.
HelloController.class
import org.springframework.ui.Model;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController // 컨트롤러를 JSON을 반환하는 컨트롤러로 만들어줍니다
public class HelloController {
// HTTP Method인 Get의 요청을 받을 수 있는 API를 만들어줍니다. 이 프로젝트는 /hello2 주소로 요청이 오면 문자열 hello22 를 반환하는 기능을 가지게되었습니다. (@RestController라서)
@GetMapping("/hello2")
public String hello(Model model) {
return "hello22";
}
}
이제 테스트코드를 추가 합니다.
HelloControllerTest.class
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.test.context.junit4.SpringRunner;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
@RunWith(SpringRunner.class) // SpringRunner라는 스프링 실행자를 사용합니다. 즉 스프링 부트 테스트와 JUnit 사이에 연결자 역할을 합니다.
@WebMvcTest(controllers = HelloController.class)
public class HelloControllerTest {
@Autowired // 스프링이 관리하는 빈(Bean)을 주입 받습니다.
private MockMvc mvc; // 스프링 MVC테스트의 시작점. 이 클래스를 통해 HTTP GET,POST 등에 대한 API 테스트를 할 수 있습니다
@Test
public void hello가_리턴된다() throws Exception {
String str = "hello22";
mvc.perform(get("/hello2")) // MockMvc를 통해 /hello2 주소로 HTTP GET 요청을 합니다
.andExpect(status().isOk()) // 흔히 알고 있는 200,404,500 등의 상태를 검증합니다. 여기선 OK 즉, 200인지 검증합니다.
.andExpect(content().string(str)); // HelloController에서 @RestController일때 데이터값 "hello22"를 리턴하기 때문에 이 값이 맞는지 검증합니다.
}
}
테스트 코드를 실행합니다.
localhost:8080/hello2 주소에 요청이 완료 되고 Http 상태코드가 200 정상으로 나오고 데이터 값도 같다면 테스트가 통과 됩니다. 아래와 같이 테스트가 완료 되었음을 확인할수 있습니다.
이번에는 실패 케이스를 확인해보겠습니다.
위의 str 값을 hello3으로 변경후 테스트코드를 실행 하면 테스트 실패 화면이 아래와 같이 발생합니다.
응답 값이 hello3이 예상되었지만 실제 hello22 값이 응답되어 데이터 값이 달라 테스트에 실패 되었습니다.
이번에는 테스트 코드를 실행하지 않고 브라우저에서 직접 화면을 확인해보겠습니다.
Application.class를 실행해주고 브라우저에서 localhost:8080/hello2 주소를 접속합니다.
HelloController.class 의 리턴값 hello22를 확인할 수 있습니다. 테스트 코드에서 기댓값을 hello3으로 돌리고 테스트 하면 실제 데이터값 hello22 와는 다르기 때문에 테스트가 실패 합니다.
이렇게 테스트 코드를 사용하면 내가 Application 클래스에서 톰캣을 돌려서 브라우저에서 직접 확인 하지 않고 @Test만 실행해도 주소 요청과 응답값이 맞는지 확인이 가능합니다.
참고자료 : 이동욱님의 '스프링 부트와 AWS로 혼자 구현하는 웹서비스' 서적
'- 서버 > springboot' 카테고리의 다른 글
스트링부트에서 JPA로 데이터베이스 다루기(1) (0) | 2024.01.02 |
---|---|
인텔리제이 롬복 추가하기 (0) | 2024.01.01 |
인텔리제이 .gitignore 사용하기 (0) | 2023.12.30 |
spring initializer 사용법 (0) | 2023.12.28 |
ioc (Inversion of Control) 소개 (0) | 2023.12.23 |