Notice
Recent Posts
Recent Comments
Link
«   2025/01   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30 31
Archives
Today
Total
관리 메뉴

개발자되기 프로젝트

JUnit-2(spring, lombok 활용) 본문

Spring Boot

JUnit-2(spring, lombok 활용)

Seung__ 2021. 5. 22. 16:32
JUnit-1에서 작성한 내용을 spring에서는 어떻게 작성해야 하는지 알아보자.

 

 

1. DollarCalculator 수정


  

먼저 Spring에서 bean으로 관리하기 위해 @Component 지정.

 

그리고 이전 코드에서는 marketApi객체를 생성자에서 주입받아서 사용을 했었다.

 

DollarCalculator class가 @Component기 때문에 MareketApi class도 마찬가지로 @Component등록이 필요하다.

 

참고로 @RequiredArgsContructor는 final, @NotNull인 인필드 값만 생성자에 주입을 시켜준다.

@Component
@RequiredArgsConstructor
public class DollarCalculator implements ICalculator {

    private int price = 1;

    private final MarketApi marketApi; //@RequiredArgsContructor,,, final 지정..?

    @Override
    public void init(){
        this.price = marketApi.connect();
    }

    @Override
    public int sum(int x, int y) {
        init();
        x *=price;
        y*=price;
        return x+y;
    }

    @Override
    public int minus(int x, int y) {
        init();
        x *=price;
        y*=price;
        return x-y;
    }
}

 

2. Calculator class 수정


이 클래스도 마찬가지로 @Component로 지정한다.

이 클래스는 ICalculator 객체를 사용하는데, ICalculator interface의 후보군은 현재 DollarCalculator class밖에 없다.

따라서 spring에서 자동으로 DollarCalculator를 주입하게 된다.

@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 minus(int x, int y){

        this.iCalculator.init();
        return this.iCalculator.minus(x, y);
    }
}

 

3. Controller 작성


* 들어가기 전에 Dto를 작성해보자.(Request, Response 객체)

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req {

    private int x;
    private int y;

}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Res {
    private int result;
    private Body response;


	//JSON에 depth를 주기위해 조금 복잡하게
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Body{
        private String resultCode = "OK";
    }
}

 

calculator는 현재 @Component  Calculator 말고 후보군이 없음.

@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.minus(req.getX(), req.getY());

        Res res = new Res();
        res.setResult(result);
        res.setResponse(new Res.Body());

        return res;
    }
}

 

 

4. test 코드 작성


  * 주의사항 : test의 package가 실제 코드의 package, Application과 ApplicationTests 위치가 일치해야 인식 가능.

  * 다른 코드도 동일한 위치에 작성해준다.

 

4-1. SpringCalculatorApplicationTests 수정


 

@SpringBootTest 를 붙여주면 실질적으로 Spring container가 올라가면서 전체적인 테스트가 가능해짐.

@SpringBootTest//
class SpringCalculatorApplicationTests {

    @Test
    void contextLoads() {
    }

}

 

 

5.  DollarCalcualtorTest 작성하기


 

DollarCalcualtor test를 위해서는 MarketApi, DallarCalculator가 필요함! import 시키자.

그리고 MarketApi는 위에서 @Component로 지정했다. 따라서 mocking처리를 위해서는 @MockBean으로 지정한다.

 

참고) @Autowired : spring이 관리하는 bean중 해당 객체의 타입과 일치하는 객체를 주입함.

@Import({MarketApi.class, DollarCalculator.class})
@SpringBootTest //spring boot 붙이는 순간 모든 bean이 등록됨.위에 import생략 가능
public class DollarCalculatorTest {

    @MockBean //bean으로 관리되어있으니 ..
    private MarketApi marketApi;

    //스프링이 관리하고 있는 bean을 받겠다.
    @Autowired //???뭐하는애냐
    private DollarCalculator dollarCalculator;

    @Test
    public void dollarCalculatorTest(){

        Mockito.when(marketApi.connect()).thenReturn(3000);

        int sum = dollarCalculator.sum(10, 10);
        int minus = dollarCalculator.minus(10, 10);
        Assertions.assertEquals(60000, sum);
        Assertions.assertEquals(0, minus);
    }

}

예상한 결과와 일치했당.

여기까지 Calculator가 정상적으로 작동하는 것을 test 완료했다.

 

이어서 Controller가 정상적으로 작동하는지 확인해보자.

 

 

6. CalculatorApiControllerTest 작성


* 들어가기 전에 Dto를 작성해보자.(Request, Response 객체)

 

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req {

    private int x;
    private int y;

}
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Res {
    private int result;
    private Body response;


	//JSON에 depth를 주기위해 조금 복잡하게
    @Data
    @NoArgsConstructor
    @AllArgsConstructor
    public static class Body{
        private String resultCode = "OK";
    }
}

 

Web에서 테스트를 할 예정이기 때문에! @webMvcTest(테스트할 class) 붙여준다.

그리고 @webMvcTest는 @SpringBootTest와는 다르게 web에 필요한 것들만 로딩을 시키기 때문에, resource 줄일 수 있당.

MocMvc란? 웹 어플리케이션을 서버에 배포하지 않고 spring MVC의 동작을 재현할 수 있도록 하는 class.
@AutoConfigureWebMvc  : MVC와 관련된 Bean을 올려줌.
MockMvc.perfom() : 요청을 전송하고 결과를 ResultActiosns 객체를 가져온다. andExpect()기능 제공.
전송할 request를 build하는법?  MockMvcRequsestBuilder.method(uri).queryPara... 등등
ResultMatcher : 실행된 결과와 예상 값을 매칭시켜 준다.

controller가 작동하기 위해서는 Calculator와 DollarCalculator import가 필요하다.

@WebMvcTest(CalculatorApiController.class)
@AutoConfigureWebMvc //뭐하ㅡㄴ애냐
@Import({Calculator.class, DollarCalculator.class})
public class CalculatorApiControllerTest {

    @MockBean
    private MarketApi marketApi;

    @Autowired //Mvc를 Mocking처리하고 주입 받겠다!
    private MockMvc mockMvc;


    //각 test 실행 전에 초기화 시킬꺼야
    @BeforeEach
    public void init(){
        Mockito.when(marketApi.connect()).thenReturn(3000);
    }

    @Test
    public void sumTest() throws Exception {
        //http://localhost:8080/api/sum

        //parameter


        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) //Json형식을 입력받기 위해 지정
                .content(json)
        ).andExpect(
                MockMvcResultMatchers.status().isOk()
        ).andExpect(
				//json path에서 result의 value는 0이어야함
                MockMvcResultMatchers.jsonPath("$.result").value("0")
        ).andExpect(MockMvcResultMatchers.jsonPath("$.response.resultCode").value("OK")
        ).andDo(MockMvcResultHandlers.print());

    }
}

 

'Spring Boot' 카테고리의 다른 글

Swagger  (0) 2021.05.30
Mock MVC  (0) 2021.05.22
Lombok  (0) 2021.05.22
JUnit-3 : Jacoco  (0) 2021.05.22
Junit-1  (0) 2021.05.22
Comments