package com.example.springcalculator.component;
public interface ICalculator {
int sum(int x, int y);
int minus(int x, int y);
}
package com.example.springcalculator.component;
import org.springframework.stereotype.Component;
@Component
public class Calculator {
private ICalculator iCalculator;
public Calculator(ICalculator iCalculator) {
this.iCalculator = iCalculator;
}
public int sum(int x, int y) {
return this.iCalculator.sum(x, y);
}
public int mius(int x, int y) {
return this.iCalculator.minus(x, y);
}
}
package com.example.springcalculator.component;
import org.springframework.stereotype.Component;
// MarketApi가 주입을 받는 경우일 경우 MarketApi도 Component가 되어야 한다
@Component
public class MarketApi {
public int connect() {
// naver
// kakao
return 1100;
}
}
package com.example.springcalculator.component;
import org.springframework.stereotype.Component;
@Component
public class DollorCalculator implements ICalculator {
private int price = 1;
private MarketApi marketApi;
// MarketApi가 주입을 받는 경우일 경우 MarketApi도 Component가 되어야 한다
public DollorCalculator(MarketApi marketApi) {
this.marketApi = marketApi;
}
public void init() {
this.price = marketApi.connect();
}
@Override
public int sum(int x, int y) {
x *= price;
y *= price;
return x+y;
}
@Override
public int minus(int x, int y) {
x *= price;
y *= price;
return x-y;
}
}
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class CalculatorApiController {
private final Calculator calculator;
@GetMapping("/sum")
public int sum(@RequestParam int x, @RequestParam int y) {
return calculator.sum(x, y);
}
@GetMapping("/minus")
public int minus(@RequestParam int x, @RequestParam int y) {
return calculator.mius(x, y);
}
}
package com.example.springcalculator.component;
public interface ICalculator {
void init();
int sum(int x, int y);
int minus(int x, int y);
}
package com.example.springcalculator.component;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class Calculator {
private final ICalculator iCalculator;
public int sum(int x, int y) {
this.iCalculator.init();
return this.iCalculator.sum(x, y);
}
public int mius(int x, int y) {
this.iCalculator.init();
return this.iCalculator.minus(x, y);
}
}
package com.example.springcalculator.component;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class DollorCalculator implements ICalculator {
private int price = 1;
private final MarketApi marketApi;
@Override
public void init() {
this.price = marketApi.connect();
}
@Override
public int sum(int x, int y) {
x *= price;
y *= price;
return x+y;
}
@Override
public int minus(int x, int y) {
x *= price;
y *= price;
return x-y;
}
}
test 폴더를 활용하며 main 폴더랑 패키지랑 파일 위치가 일치해야 한다
test도 서버처럼 동작을 한다
@SpringBootTest
DollorCalculatorTest.java
package com.example.springcalculator.component;
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.mock.mockito.MockBean;
// 내가 필요한 클래스를 import
//@Import({MarketApi.class, DollorCalculator.class})
// @SpringBootTest를 해주면 모든 객체들이 Bean에 할당이 되기에 import 안해줘도 된다
@SpringBootTest
public class DollorCalculatorTest {
// Spirng에서는 Mock이 아닌 MockBean을 사용하는데 그건 Spring Bean으로 관리 되기 때문이다
@MockBean
private MarketApi marketApi;
@Autowired
private DollorCalculator dollorCalculator;
@Test
public void dollorCalculatorTest() {
Mockito.when(marketApi.connect()).thenReturn(3000);
dollorCalculator.init();
int sum = dollorCalculator.sum(10, 10);
int minus = dollorCalculator.minus(10, 10);
Assertions.assertEquals(60000, sum);
Assertions.assertEquals(0, minus);
}
}
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import com.example.springcalculator.component.DollorCalculator;
import com.example.springcalculator.component.MarketApi;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
// web test(test 할 클래스)
@WebMvcTest(CalculatorApiController.class)
@AutoConfigureWebMvc
@Import({Calculator.class, DollorCalculator.class})
public class CalculatorApiControllerTest {
@MockBean
private MarketApi marketApi;
// mvc를 모킹으로 테스트하겠다
@Autowired
private MockMvc mockMvc;
@BeforeEach
public void init() {
Mockito.when(marketApi.connect()).thenReturn(3000);
}
@Test
public void sumTest() throws Exception {
// http://localhost:8080/api/sum?x=&y=
mockMvc.perform(
MockMvcRequestBuilders.get("http://localhost:8080/api/sum")
.queryParam("x","10")
.queryParam("y", "10")
).andExpect(
MockMvcResultMatchers.status().isOk()
).andExpect(
MockMvcResultMatchers.content().string("60000")
).andDo(MockMvcResultHandlers.print());
}
}
package com.example.springcalculator.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Req {
private int x;
private int y;
}
package com.example.springcalculator.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Res {
// 뎁스 추가
private int result;
private Body response;
@Data
@NoArgsConstructor
@AllArgsConstructor
public static class Body {
private String resultCode = "OK";
}
}
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import com.example.springcalculator.dto.Req;
import com.example.springcalculator.dto.Res;
import lombok.RequiredArgsConstructor;
import org.springframework.web.bind.annotation.*;
@RestController
@RequestMapping("/api")
@RequiredArgsConstructor
public class CalculatorApiController {
private final Calculator calculator;
@GetMapping("/sum")
public int sum(@RequestParam int x, @RequestParam int y) {
return calculator.sum(x, y);
}
@PostMapping("/minus")
public Res minus(@RequestBody Req req) {
int result = calculator.mius(req.getX(), req.getY());
Res res = new Res();
res.setResult(result);
res.setResponse(new Res.Body());
return res;
}
}
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import com.example.springcalculator.component.DollorCalculator;
import com.example.springcalculator.component.MarketApi;
import com.example.springcalculator.dto.Req;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureWebMvc;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.mock.mockito.MockBean;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
// web test(test 할 클래스)
@WebMvcTest(CalculatorApiController.class)
@AutoConfigureWebMvc
@Import({Calculator.class, DollorCalculator.class})
public class CalculatorApiControllerTest {
@MockBean
private MarketApi marketApi;
// mvc를 모킹으로 테스트하겠다
@Autowired
private MockMvc mockMvc;
@BeforeEach
public void init() {
Mockito.when(marketApi.connect()).thenReturn(3000);
}
@Test
public void sumTest() throws Exception {
// http://localhost:8080/api/sum?x=&y=
mockMvc.perform(
MockMvcRequestBuilders.get("http://localhost:8080/api/sum")
.queryParam("x","10")
.queryParam("y", "10")
).andExpect(
MockMvcResultMatchers.status().isOk()
).andExpect(
MockMvcResultMatchers.content().string("60000")
).andDo(MockMvcResultHandlers.print());
}
@Test
public void minusTest() throws Exception {
Req req = new Req();
req.setX(10);
req.setY(10);
String json = new ObjectMapper().writeValueAsString(req);
mockMvc.perform(
MockMvcRequestBuilders.post("http://localhost:8080/api/minus")
.contentType(MediaType.APPLICATION_JSON)
.content(json)
).andExpect(
MockMvcResultMatchers.status().isOk()
).andExpect(
MockMvcResultMatchers.jsonPath("$.result").value("0")
).andExpect(
// 뎁스 접근
MockMvcResultMatchers.jsonPath("$.response.resultCode").value("OK")
).andDo(MockMvcResultHandlers.print());
}
}