Application μ½λμ ν μ€νΈ μ½λ μμ±νκΈ°
Application μ½λ μμ±νκΈ°
Application ν΄λμ€λ springboot νλ‘μ νΈμ λ©μΈ ν΄λμ€κ° λλ€. src/main/java μ com.study.springbootaws ν¨ν€μ§λ₯Ό μμ±νλ€. ν¨ν€μ§λͺ μ λ³΄ν΅ νμ¬ λλ©μΈμ μμμΌλ‘ λ§λ λ€. κ·Έ μλμ Application class λ₯Ό μμ±νκ³ μλμ²λΌ λ΄μ©μ μμ±νλ€.
src/main/java/com.study.springbootaws/Application
package com.study.springbootaws;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
//νλ‘μ νΈμ μμμ . μ€νλ§λΆνΈ, Bean μ½κΈ°/μμ± λ± μλμΌλ‘ μ€μ ν΄μ£Όλ μ΄λ
Έν
μ΄μ
@SpringBootApplication
public class Application {
public static void main(String[] args) {
//λ΄μ₯ WAS μ€ν
SpringApplication.run(Application.class, args);
}
}
@SpringbootApplicaiton μ΄λ Έν μ΄μ λλΆμ μ€νλ§λΆνΈμ μλμ€μ , Bean μ½κΈ°/μμ±μ λͺ¨λ μλμΌλ‘ μ€μ λλ€. λ μ΄ μ΄λ Έν μ΄μ μ΄ μλ μμΉλΆν° νλ‘μ νΈλ₯Ό μ½μ΄κ°λ―λ‘, Application ν΄λμ€λ νμ μ΅μλ¨μ μμΉν΄μΌλ§ νλ€.
SpringApplication.run λ©μλλ λ΄μ₯ WAS λ₯Ό μ€ννλ€. μ΄λ κ² λλ©΄ μλ²μ ν°μΊ£μ μ€μΉν νμ μμ΄ μ€νλ§ λΆνΈλ‘ λ§λ€μ΄μ§ μ€ννμΌ(Jar) λ‘ μ€ννλ©΄ λλ€. λ΄μ₯ WAS λ₯Ό μ°μ§ μμλ λμ§λ§, μΈμ μ΄λμλ κ°μ νκ²½μμ μ€νλ§ λΆνΈλ₯Ό λ°°ν¬ν μ μκΈ° λλ¬Έμ μ¬μ©μ΄ κΆμ₯λλ€.
ν μ€νΈ μ½λ μμ±νκΈ°
ν μ€νΈ μ½λκ° λ¬΄μμ΄κ³ μ νμνμ§λ π TDD (Test Driven Development), ν μ€νΈ μ£Όλ κ°λ°μ΄λ? μ μ°Έκ³ ν΄μ£ΌμΈμ.
src/main/java/com.study.springbootaws/web/HelloController
λ¨Όμ ν μ€νΈν 컨νΈλ‘€λ¬λ₯Ό μ κ²½λ‘λ₯Ό λ°λΌ λ§λ λ€. μ°Έκ³ λ‘ @RestController λ 컨νΈλ‘€λ¬λ₯Ό JSON μ λ°ννλ 컨νΈλ‘€λ¬λ‘ λ§λ€μ΄μ€λ€. μμ μ JSONμ λ°ννλ €λ©΄ @ResponseBody λ₯Ό κ° λ©μλλ§λ€ μ μΈν΄μΌ νλ€. @GetMapping λ μ΅μ λ¬Έλ²μ΄λ€. λμ @GetMappingμ λ©μλ λ¨μμμλ§ μΈ μ μκ³ μ΄μ μ @RequestMapping μ ν΄λμ€ λ¨μκΉμ§ μΈ μ μλ€.
package com.study.springbootaws.web;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
//JSON μ λ°ννλ 컨νΈλ‘€λ¬λ‘ λ§λ€μ΄μ€
@RestController
public class HelloController {
@GetMapping("/hello") // = @RequestMapping(method = RequestMethod.GET)
public String hello() {
return "hello";
}
}
build.gradle
JUnit μ Java ν μ€νΈ μ½λ μμ±μ λμμ£Όλ νλ μμν¬λ€. μ± μμλ JUnit4λ‘ μ§ννμ§λ§ λλ JUnit5λ‘ μ§νν κ²μ΄λ€. λ§μ½ JUnit4λ₯Ό μ΄μ©νκ³ μΆλ€λ©΄ build.gradle μ μλ μ½λλ₯Ό μΆκ°ν΄μ£Όκ³ ν μ€νΈμ½λλ₯Ό μ± κ³Ό κ°μ΄ μ°λ©΄ λλ€.
dependencies {
...
implementation 'junit:junit:4.13.1'
...
}
JUnit5 λ Springboot 2.2.x λ²μ μ λ΄μ₯λμ΄ μμ΄μ μΆκ°ν νμκ° μλ€.
src/test/java/com.study.springbootaws/web/HelloControllerTest
μ΄μ μ κ²½λ‘μ 컨νΈλ‘€λ¬λ₯Ό ν μ€νΈν ν μ€νΈμ½λλ₯Ό μμ±νμ. μ°Έκ³ λ‘ @RunWith μ JUnit4 μ λ¬Έλ²μΌλ‘, JUnit ν μ€νΈλ₯Ό μ€νλ§ λΆνΈ ν μ€νΈλ‘ νμ₯μμΌμ£Όλ μν μ νλ€. JUnit5 λ‘ λμ΄μ€λ©° @ExtendWith λΌλ μ΄λ Έν μ΄μ μΌλ‘ λ°λμμΌλ @SrpringbootTest, @WebMvcTest κ°μ μ΄λ Έν μ΄μ μ μ΄λ―Έ λ΄μ₯λμ΄ μμΌλ―λ‘ μλ΅ν μ μλ€.
package com.study.springbootaws.web;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.test.web.servlet.MockMvc;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
//Springbootμ λͺ¨λ λΉμ λ‘λνμ§ μκ³ controller κ΄λ ¨ μ½λλ§ ν
μ€νΈν λ μ¬μ©. λ¨, Service, Component, Repositoryλ μ¬μ©x
@WebMvcTest(HelloController.class)
public class HelloControllerTest {
@Autowired //Bean μλ μ£Όμ
private MockMvc mvc; //μΉ API ν
μ€νΈ(GET, POST λ±)μ μ¬μ©. μ€νλ§ MVC ν
μ€νΈμ μμμ
@Test
public void returnHello() throws Exception {
String hello = "hello";
mvc.perform(get("/hello")) // /hello μ£Όμλ‘ get μμ²
.andExpect(status().isOk()) //κ²°κ³Ό μ€ HTTP Header μ status code κ²μ¦.
.andExpect(content().string(hello)); //κ²°κ³Ό μ€ λ³Έλ¬Έ κ²μ¦.
}
}
ν μ€νΈ μ€ν
μλ μ΄λ―Έμ§μ²λΌ Run 'returnHello()' λ₯Ό ν΄λ¦νλ©΄ ν°λ―Έλμ κ²°κ³Όκ° λνλλ€. λ§μ½ Execution failed for task ':test' μλ¬κ° λλ€λ©΄ π [π§ νΈλ¬λΈμν ] IntelliJ JUnit ν μ€νΈ μ€ Execution failed for task ':test' μλ¬ κ²μλ¬Όμ νμΈνμ.
ν μ€νΈκ° ν΅κ³Όλλ€!
둬볡μΌλ‘ λ³ννκ³ ν μ€νΈν΄λ³΄κΈ°
μ§κΈμ μμ κ·λͺ¨μ§λ§, ν° κ·λͺ¨μ νλ‘μ νΈμ 둬볡μ μΆκ°νλ©΄ μ΄λ€ μ½λμμ μλ¬κ° λλμ§ μ λλμ§ νμΈνκΈ° μ½μ§ μμ κ²μ΄λ€. κ·Έλ¬λ ν μ€νΈ μ½λκ° μ°λ¦¬μ μ½λλ₯Ό μ§μΌμ£Όλ―λ‘, ν μ€νΈ μ½λλ§ λλ €λ³΄λ©΄ λ¬Έμ κ° μκΈ°λμ§ μ μ μλ€. 둬볡μΌλ‘ λ³νν ν ν μ€νΈλ₯Ό νλ² ν΄λ³Ό κ²μ΄λ€.
둬볡 μ€μ
둬볡μ μλ° κ°λ°μ μμ£Ό μ¬μ©νλ getter, setter, construct, toStrign λ±μ μ΄λ Έν μ΄μ μΌλ‘ μλ μμ±ν΄μ£Όλ νΈλ¦¬ν λΌμ΄λΈλ¬λ¦¬λ€. μ΄μ μ plugins μμ μ€μΉνλ κ²μ²λΌ lombok νλ¬κ·ΈμΈμ μ€μΉν΄μ€λ€. λλ μ΄λ―Έ μ€μΉλμ΄ μμ΄μ κ³Όμ μ μλ΅νκ² λ€. λ¨, 둬볡 νλ¬κ·ΈμΈμ νλ²λ§ μ€μΉνλ©΄ λμ§λ§ 둬볡 μ¬μ© μ€μ μ νλ‘μ νΈλ§λ€ ν΄μ€μΌ νλ―λ‘ μλμ²λΌ μ€μ ν΄μ€λ€.
build.gradle
dependencies {
...
//gradle μ΄ λ²μ 4 λΌλ©΄
implementation 'org.projectlombok:lombok'
//gradle μ΄ λ²μ 5 λΌλ©΄
compileOnly 'org.projectlombok:lombok'
annotationProcessor 'org.projectlombok:lombok'
...
}
src/main/java/com.study.springbootaws/web/dto/HelloResponseDto
λ‘¬λ³΅μ΄ μ¬μ©λ Dto λ₯Ό μ κ²½λ‘μ μΆκ°ν΄μ€λ€.
package com.study.springbootaws.web.dto;
import lombok.Getter;
import lombok.RequiredArgsConstructor;
@Getter //λͺ¨λ νλ getter λ©μλ μμ±
@RequiredArgsConstructor //final μ΄λ @NonNull κ°μΈ λͺ¨λ νλλ₯Ό νλΌλ―Έν°λ‘ λ°λ μμ±μ μμ±
public class HelloResponseDto {
private final String name;
private final int amount;
}
src/test/java/com.study.springbootaws/web/dto/HelloResponseDtoTest
μ κ²½λ‘μ ν μ€νΈ μ½λλ₯Ό μΆκ°ν΄μ£Όκ³ μ€ννλ€. λ§μ½ not initialized in the default constructor μλ¬κ° λλ€λ©΄ gradle λ²μ μ λ§κ² lokmokμ μΆκ°νλμ§ νμΈνμ. assertThat μ λ©μλ μΈμλ‘ λ°μ value λ₯Ό κ²μ¦ν΄μ€λ€. μ°Έκ³ λ‘ Junit μ κΈ°λ³Έ assertThat μ΄ μλ assertj λ₯Ό μ¬μ©νλ€. μ΄μ λ assertj λ Assert ν΄λμ€λ₯Ό λ°ννλ―λ‘ λ©μλ μλμμ±μ΄ λκ³ μ²΄μ΄λ λ©μλ ν¨ν΄μ μ¬μ©ν μ μκΈ° λλ¬Έμ΄λ€.
package com.study.springbootaws.web.dto;
import org.junit.jupiter.api.Test;
import static org.assertj.core.api.AssertionsForClassTypes.assertThat;
public class HelloResponseDtoTest {
@Test
public void lombokTest() {
String name = "test";
int amount = 1000;
HelloResponseDto dto = new HelloResponseDto(name, amount);
//asseartThat μ λ©μλ μΈμλ‘ λ°μ value λΉκ΅ λ° κ²μ¦ν΄μ€.
//isEqualTo λ§κ³ λ greaterThan, lessThan λ±μ 체μ΄λλ κ°λ₯.
assertThat(dto.getName()).isEqualTo(name);
assertThat(dto.getAmount()).isEqualTo(amount);
}
}
λ§μ°¬κ°μ§λ‘ ν μ€νΈνλ©΄ μ λμνλ€.
HelloController μ HelloResponseDto λ₯Ό μ¬μ©νκ³ ν μ€νΈν΄λ³΄κΈ°
HelloResponseDto κ° λ¬Έμ μμ΄ λμν¨μ νμΈνμΌλ HelloController μ μ μ©ν΄λ³΄μ.
src/main/java/com.study.springbootaws/web/HelloController
HelloControlelr ν΄λμ€μ HelloReponseDto λ₯Ό μ¬μ©νλ μλ‘μ΄ κ²½λ‘λ₯Ό μλμ²λΌ μΆκ°νμ.
import org.springframework.web.bind.annotation.RequestParam;
...
@GetMapping("/hello/dto")
public HelloResponseDto helloDto(@RequestParam("name") String name, @RequestParam("amount") int amount) {
return new HelloResponseDto(name, amount);
}
...
src/test/java/com.study.springbootaws/web/HelloControllerTest
HelloControllerTest μ μΆκ°ν helloDto λ₯Ό ν μ€νΈνλ μ½λλ₯Ό μμ±νλ€. jsonPath λ μλ΅κ°μ json νλλ‘ κ²μ¦ν μ μλ λ©μλλ€.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
...
@Test
public void returnHelloDto() throws Exception {
String name = "hello";
int amount = 1000;
mvc.perform(get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name").value(name)) //$ => 루νΈ, .name => ['name'] νμμμ
.andExpect(jsonPath("$.amount").value(amount));
}
...
ν μ€νΈλ₯Ό λ리면 무μ¬ν ν΅κ³Όνλ€!