JUnit
: Java기반의 단위테스트를위한 프레임워크
Annotation 기반으로테스트를지원하며, Assert를 통하여, 예상, 실제 를 통해 검증
* 단위테스트
: 작성한코드가 기대하는 대로 동작을 하는지 검증 하는 절차
* TDD(Test-Driven Development)
: 테스트주도개발에서 사용하지만, 코드의 유지보수및 운영환경에서의 에러를 미리 방지하기 위해서 단위 별로 검증하는 프레임워크
JUnit
ICalculator 인터페이스
public interface ICalculator {
int sum(int x, int y);
int minus(int x, int y);
}
Calculator 클래스
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 minus(int x, int y){
return this.iCalculator.minus(x,y);
}
}
DollarCalculator 클래스
public class DollarCalculator implements ICalculator{
private int price = 1;
/* 환율값을 가져오기 위한 API */
private MarketApi marketApi;
public DollarCalculator(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;
}
}
KRWCalculator 클래스
public class KRWCalculator implements ICalculator{
private int price = 1;
@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;
}
}
MarketApi 클래스
public class MarketApi {
public int connect(){
return 1300;
}
}
Main 클래스
public class Main {
public static void main(String[] args) {
/* ICalculator를 구현체를 받아 Calculator 생성 */
//Calculator calculator = new Calculator(new KRWCalculator());
//System.out.println(calculator.sum(10,10));
/* 달러 계산기 */
MarketApi marketApi = new MarketApi();
DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
// 환율 계산
dollarCalculator.init();
// 계산기 구현
Calculator calculator = new Calculator(dollarCalculator);
System.out.println(calculator.sum(10,10));
}
}
DollarCalculatorTest
import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.mockito.junit.jupiter.MockitoExtension;
/* Mockito */
/*
* 객체를 쉽게 만들고 , 관리, 검증 할 수 있는 방법을 제공하는 프레임워크
* Mock : 진짜 객체와 비슷하게 동작하지만, 프로그래머가 직접 관리하는 객체
* https://site.mockito.org/
* mockito-core : 기본 라이브러리
* mockito-junit-jupiter : junit과 연동해서 사용하는 확장구현체
*/
/* @ExtendWith */
/*
* 명시적으로 Mockito를 사용함을 뜻함
*/
@ExtendWith(MockitoExtension.class)
public class DollarCaculatorTest {
/* Mock 어노테이션을 사용하여 객체를 생성 */
@Mock
public MarketApi marketApi;
@BeforeEach
public void init(){
/* mock()를 사용하여 원하는 Type를 매개변수로 받아 원하는 객체를 만들 수 있음 */
// MarketApi marketApi = mock(MarketApi.class);
/* lenient() 행동 정의하기 */
/* when() 어느시점 */
/* thenReturn() 리턴값 정의 */
Mockito.lenient().when(marketApi.connect()).thenReturn(3000);
}
@Test
public void dollarTest(){
/* 달러 계산기 */
MarketApi marketApi = new MarketApi();
DollarCalculator dollarCalculator = new DollarCalculator(marketApi);
// 환율 계산
dollarCalculator.init();
// 계산기 구현
Calculator calculator = new Calculator(dollarCalculator);
System.out.println(calculator.sum(10,10));
/* Assertions 클래스 */
Assertions.assertEquals(26000,calculator.sum(10,10));
Assertions.assertEquals(0,calculator.minus(10,10));
}
/* Mockito를 사용한 Test */
@Test
public void MockTest(){
/* Mock을 사용한 MacketApi 사용 */
DollarCalculator dollarCalculator = new DollarCalculator(this.marketApi);
// 환율 계산
dollarCalculator.init();
// 계산기 구현
Calculator calculator = new Calculator(dollarCalculator);
/* Assertions
* 단정문으로 만약 성공하지 않으면 테스트를 실패처하기위한 Junit5 클래스
* assertEquals(기대값, 행동)
* */
Assertions.assertEquals(60000,calculator.sum(10,10));
System.out.println("60000");
Assertions.assertEquals(0,calculator.minus(10,10));
}
}
Spring JUnit
ICalculator 인터페이스
package com.example.springcalculator.component;
public interface ICalculator {
void init();
int sum(int x, int y);
int minus(int x, int y);
}
Calculator 클래스
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 minus(int x, int y){
this.iCalculator.init();
return this.iCalculator.minus(x,y);
}
}
DollarCalculator 클래스
package com.example.springcalculator.component;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Component;
@Component
@RequiredArgsConstructor
public class DollarCalculator 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;
}
}
MarketApi 클래스
package com.example.springcalculator.component;
import org.springframework.stereotype.Component;
@Component
public class MarketApi {
public int connect(){
return 1300;
}
}
CalculatorController 클래스
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import com.example.springcalculator.component.ICalculator;
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 CalculatorController {
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.setResVal(result);
Res.Body body = new Res.Body();
body.setResultCode("OK");
res.setResBody(body);
return res;
}
}
package com.example.springcalculator.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Req {
private int x;
private int y;
}
package com.example.springcalculator.dto;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Res {
private int resVal;
private Body resBody;
@Data
@AllArgsConstructor
@NoArgsConstructor
public static class Body{
private String resultCode;
}
}
DollarCalculatorTest
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 org.springframework.context.annotation.Import;
@SpringBootTest
//@Import({MarketApi.class, DollarCalculator.class}) // 일부클래스만 불러올때
public class DollarCalculatorTest {
@MockBean
private MarketApi marketApi;
@Autowired
private Calculator calculator;
@Test
public void dollarTest(){
Mockito.when(marketApi.connect()).thenReturn(3000);
int sum = calculator.sum(10,10);
int minus = calculator.minus(10,10);
Assertions.assertEquals(60000,sum);
Assertions.assertEquals(0,minus);
}
}
CalculatorControllerTest
package com.example.springcalculator.controller;
import com.example.springcalculator.component.Calculator;
import com.example.springcalculator.component.DollarCalculator;
import com.example.springcalculator.component.MarketApi;
import com.example.springcalculator.dto.Req;
import com.fasterxml.jackson.core.JsonProcessingException;
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;
@WebMvcTest(CalculatorController.class) // 필요한 Web만 가져와서 테스트
@AutoConfigureWebMvc
@Import({Calculator.class, DollarCalculator.class,})
public class CalculatorControllerTest {
@MockBean
private MarketApi marketApi;
@Autowired
private MockMvc mockMvc;
@BeforeEach
public void init(){
Mockito.when(marketApi.connect()).thenReturn(3000);
}
@Test
public void sumTest(){
try {
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());
} catch (Exception e) {
throw new RuntimeException(e);
}
}
@Test
public void minusTest(){
Req req = new Req();
req.setX(10);
req.setY(10);
String json = null;
try {
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("$.resVal").value("0")
).andExpect(
MockMvcResultMatchers.jsonPath("$.resBody.resultCode").value("OK")
).andDo(MockMvcResultHandlers.print());
} catch (JsonProcessingException e) {
throw new RuntimeException(e);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
}
'OOP > Java' 카테고리의 다른 글
Java 정규 표현식(Regular Expression) (0) | 2023.11.27 |
---|---|
Optional이란? (0) | 2023.11.24 |
객체지향 4대 특성 (0) | 2022.07.31 |
Thread (0) | 2022.05.29 |
직렬화 (0) | 2022.05.29 |