[Spring] 애플리케이션 구축하기
이번 포스팅에서는 애플리케이션을 구축하고 유용한 서비스를 이용하여 프로젝트를 관리하는 방법에 대해서 알아보도록 하겠습니다.
Spring Initializr
Spring Initializr로 접속을 해주시고, 다음과 같이 Artifact와 의존성을 작성해주세요!
Generate를 받아주시고, 프로젝트의 압축을 풀어주세요.
간단한 웹 애플리케이션 만들기
이제 간단한 웹 애플리케이션을 만들어 보도록 하겠습니다.
src\main\java\com\example\springboot\HelloController.java 파일을 만들어주시고
아래와 같이 내용을 작성해 주세요.
package com.example.springboot;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.bind.annotation.RequestMapping;
@RestController
public class HelloController {
@RequestMapping("/")
public String index() {
return "Greetings from Spring Boot!";
}
}
컨트롤러가 @RestController 라고 명시되어 Spring MVC 에서 웹 요청을 처리할 수 있습니다.
@RequestMapping 은 "/" 경로를 index() 메소드에 매핑합니다.
브라우저 또는 명령줄에서 curl(http://localhost:8080)을 사용하여 호출하면 메소드가 순수 텍스트를 리턴합니다.
@RestController는 @Controller와 @ResponseBody를 결합한 것으로, 웹 요청에 대해 뷰가 아니라 데이터를 리턴합니다.
다음으로 Application 클래스입니다.
Controller와 같은 위치에 이미 Application이 생성 되어 있을 것입니다.
기생성된 클래스의 내용을 아래와 같이 수정해 주세요.
CommandLineRunner에서 Spring이 자동으로 추가해준 Bean을 출력해줍니다.
이를 통해 우리는 Spring이 어떤 Bean을 출력해 주는지 확인해볼 수 있습니다.
package com.example.springboot;
import java.util.Arrays;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.Bean;
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
@Bean
public CommandLineRunner commandLineRunner(ApplicationContext ctx) {
return args -> {
System.out.println("Let's inspect the beans provided by Spring Boot:");
String[] beanNames = ctx.getBeanDefinitionNames();
Arrays.sort(beanNames);
for (String beanName : beanNames) {
System.out.println(beanName);
}
};
}
}
애플리케이션 실행하기
gradlew bootrun
위의 명령어를 터미널에서 입력하시면 애플리케이션이 실행됩니다.
터미널에서 다음과 같은 결과를 보실 수 있는데, 이 결과는 Spring 이 자동으로 추가해준 Bean 설정입니다.
Let's inspect the beans provided by Spring Boot:
application
beanNameHandlerMapping
defaultServletHandlerMapping
dispatcherServlet
embeddedServletContainerCustomizerBeanPostProcessor
handlerExceptionResolver
helloController
httpRequestHandlerAdapter
messageSource
mvcContentNegotiationManager
mvcConversionService
mvcValidator
org.springframework.boot.autoconfigure.MessageSourceAutoConfiguration
org.springframework.boot.autoconfigure.PropertyPlaceholderAutoConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$DispatcherServletConfiguration
org.springframework.boot.autoconfigure.web.EmbeddedServletContainerAutoConfiguration$EmbeddedTomcat
org.springframework.boot.autoconfigure.web.ServerPropertiesAutoConfiguration
org.springframework.boot.context.embedded.properties.ServerProperties
org.springframework.context.annotation.ConfigurationClassPostProcessor.enhancedConfigurationProcessor
org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor
org.springframework.context.annotation.internalAutowiredAnnotationProcessor
org.springframework.context.annotation.internalCommonAnnotationProcessor
org.springframework.context.annotation.internalConfigurationAnnotationProcessor
org.springframework.context.annotation.internalRequiredAnnotationProcessor
org.springframework.web.servlet.config.annotation.DelegatingWebMvcConfiguration
propertySourcesBinder
propertySourcesPlaceholderConfigurer
requestMappingHandlerAdapter
requestMappingHandlerMapping
resourceHandlerMapping
simpleControllerHandlerAdapter
tomcatEmbeddedServletContainerFactory
viewControllerHandlerMapping
자세히 살펴보시면 DispatcherServletConfiguration과 EmbeddedTomcat을보실 수 있습니다.
실행된 페이지는 아래와 같습니다.
유닛테스트 추가하기
자 이제 유닛 테스트를 추가하여 단위별로 기능을 실행하고 점검하여 기능들이 의도에 맞게 올바르게 동작하는지 테스트 해보겠습니다.
build.gradle에 다음과 같은 Implementation이 추가되어 있는지 확인해 주세요.
만약 추가되어 있지 않다면 추가해주세요!
testImplementation('org.springframework.boot:spring-boot-starter-test') {
exclude group: 'org.junit.vintage', module: 'junit-vintage-engine'
}
이제 endpoint를 통한 서블릿 요청 및 응답을 테스트하는 코드를 작성합니다.
package com.example.springboot;
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.jupiter.api.Test;
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.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
@SpringBootTest
@AutoConfigureMockMvc
public class HelloControllerTest {
@Autowired
private MockMvc mvc;
@Test
public void getHello() throws Exception {
mvc.perform(MockMvcRequestBuilders.get("/").accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(content().string(equalTo("Greetings from Spring Boot!")));
}
}
MockMvc는 Spring Test에서 제공되며, builder 클래스를 통해, HTTP 요청을 DispatcherServlet으로 보내고 결과를 생성합니다.
@AutoConfigureMockMvc 및 @SpringBootTest를 사용하여 MockMvc 인스턴스를 주입합니다.
@SpringBootTest를 사용하면서 전체 애플리케이션 컨텍스트를 만듭니다. (@WebMvcTest를 사용하여 웹 레이어만 생성하도록 할 수도 있습니다.)
HTTP 요청 사이클을 확인할 수 있을 뿐만 아니라, Spring Boot 를 사용하여 간단한 풀 스택 통합 테스트를 작성할 수도 있습니다.
package com.example.springboot;
import static org.assertj.core.api.Assertions.*;
import java.net.URL;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
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;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
public class HelloControllerIT {
@LocalServerPort
private int port;
private URL base;
@Autowired
private TestRestTemplate template;
@BeforeEach
public void setUp() throws Exception {
this.base = new URL("http://localhost:" + port + "/");
}
@Test
public void getHello() throws Exception {
ResponseEntity<String> response = template.getForEntity(base.toString(),
String.class);
assertThat(response.getBody()).isEqualTo("Greetings from Spring Boot!");
}
}
내장된 서버는 webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT 에 의해 임의 포트에서 시작되며, 실제 포트는 실행 시 @LocalServerPort 를 사용하여 감지됩니다.
asserThat().isEqualTo()를 통해 반환되는 값이 원하는 값과 같은지 확인해볼 수 있습니다.
만약에 junit class not found라는 오류가 발생하면
implementation 'org.junit.platform:junit-platform-console-standalone:1.6.2'
위와 같은 implimentation을 추가해 주세요.
자 이제 단위별로 테스트를 해보도록 하겠습니다.
vscode의 테스트를 봐주시면 작성한 세가지의 테스트 클래스가 있습니다. run을 눌러 소스코드에 체크표시가 나타나는지 확인해 보세요.
만약에 체크표시가 나타나지 않는다면 새로운 창에 오류에 관한 내용을 알려줄 것입니다.
이것은 단위테스트로 제대로된 코드가 올바르게 작동하는지 알 수 있도록 고안된 것으로 올바르게 동작한다면 체크표시만 확인하시면 됩니다.
관리서비스 구축하기
비즈니스를 위한 웹 사이트 구축을 하는 경우 일부 관리 서비스를 추가해야 합니다.
Spring Boot는 actuator 모듈을 통해 여러가지 서비스(health, audits, beans 등)를 제공합니다.
build.gradle에 아래와 같은 impliment를 추가해 줍니다.
implementation 'org.springframework.boot:spring-boot-starter-actuator'
Spring Boot가 제공하는 관리 서비스 가 아래와 같이 나오게 됩니다.
management.endpoint.configprops-org.springframework.boot.actuate.autoconfigure.context.properties.ConfigurationPropertiesReportEndpointProperties
management.endpoint.env-org.springframework.boot.actuate.autoconfigure.env.EnvironmentEndpointProperties
management.endpoint.health-org.springframework.boot.actuate.autoconfigure.health.HealthEndpointProperties
management.endpoint.logfile-org.springframework.boot.actuate.autoconfigure.logging.LogFileWebEndpointProperties
management.endpoints.jmx-org.springframework.boot.actuate.autoconfigure.endpoint.jmx.JmxEndpointProperties
management.endpoints.web-org.springframework.boot.actuate.autoconfigure.endpoint.web.WebEndpointProperties
management.endpoints.web.cors-org.springframework.boot.actuate.autoconfigure.endpoint.web.CorsEndpointProperties
management.health.status-org.springframework.boot.actuate.autoconfigure.health.HealthIndicatorProperties
management.info-org.springframework.boot.actuate.autoconfigure.info.InfoContributorProperties
management.metrics-org.springframework.boot.actuate.autoconfigure.metrics.MetricsProperties
management.metrics.export.simple-org.springframework.boot.actuate.autoconfigure.metrics.export.simple.SimpleProperties
management.server-org.springframework.boot.actuate.autoconfigure.web.server.ManagementServerProperties
management.trace.http-org.springframework.boot.actuate.autoconfigure.trace.http.HttpTraceProperties
다음 명령을 실행하여 기본적인 actuator의 프로젝트 관리 기능을 확인할 수 있습니다:
- localhost:8080/actuator/health
- localhost:8080/actuator/info
- localhost:8080/actuator
왜 단위테스트와 Actuator를 사용하는가?
[Spring] Junit을 사용하여 단위테스트(Spring-Test사용)
Junit을 사용하여 단위테스트(Spring-Test사용) Junit이란? Java에서 독립된 단위테스트를 지원해주는 프레임워크 Spring-Test란? @RunWith/@ContextConfiguration 등의 어노테이션을 활용하여 Spring Framework에..
devjjo.tistory.com
https://supawer0728.github.io/2018/05/12/spring-actuator/