테스트를 잘하는 방법
예전에는.. 테스트를 직접 하나씩 클릭하고 레코딩해서 팀이 테스트만 하였다 .
(진짜 어려웠겠다는 생각을 했다.. 사실 테스트라는게 스스로 테스트 case를 생각하기 떄문에.. 어려운 부분이 많았다.
이런걸 하나하나씩 다 했다는게 진짜 대단하다 )
다 짰는데 , 그다음에 기획이 바뀌고 코드가 다시 바뀌는 경우가 굉장히 많다.
코딩 -> 리팩터링 -> 테스트 -> 개선의 반복이다.
CLASS, METHOD가 SRP를 잘 지켜야 한다.
SRP? 단일 책임 원칙으로써, 하나의 객체는 하나의 책임(기능)을 담당해야한다.
ENTITY에 사람정보 말고 갑자기 다른 기능이 있거나, 이래선 안된다.
이럴때가 TEST를 사용하기에 굉장히 유리한 상황이다! (또한, 그 크기가 너무 크지 않을때가 테스트 사용에 좋다)
Mocking을 적절하게 사용한다. -> 가짜 객체를 생성한다는 의미 완벽한 ex)는 아니지만.. db를 매번 만들 수는 없다 .
있는 '척'을 하자 !
코드 개선시, 테스트코드도 같이 진행하는 것이 좋다.
*맨날 테스트가 나는 혼자서만 했기 때문에, 시간을 낭비하는 것 처럼 느꼈지만 그러지말자.
기능의 추가와 제거에서 결정적인 역할을해 궁극적으론 시간을 야껴준다.
JAVA에서 그 기본을 받아와 + XUNIT 아키텍쳐 (테스트를 위한 프레임워크 )
CTRL+SHIFT+T로 자동생성. -> JUNIT은 순수 스프링을 위해서는 아니고, 사실은 자바를 위해서 완성된 것이다.
assertEQAULS(예측,실제 변수) -> 고프 기억하지? 같으면 통과, 안같으면 안통과를 ASSERT를 활용한것.
TEst시마다 service, 기타 등등 객체를 매번 생성해야 하는가?
@SpringBootTest 어노테이션 -> 모든 빈이 다 뜨게 된다.
그 이후 @Autowired로 원하는 class를 생성해서 사용하면 된다.
-Service test
객체를 생성해서 넣어보고, 이로 test 문제가 2가지 있다 무엇일까?
1.SOUT으로 객체를 출력해서 보는것은 그렇게 좋은 방식의 TEST는 아니다
2. 또한, 실제 객체를 이렇게 생성하는 것도, 좋은 방식의 TEST가 아니다.
@SPRINGBOOT대신 @ExtendWith(MockitoExtension.class)
@Autowired도 , @InjectMocks. -> 이 실제 객체가 사용하는애들은
@Mocks를달아준다. -> mock들의 동작 정의가 필요하다
이런 가짜 행위중 developerrepository가 findbymemberid를 한다면, 이런 가짜로 만든 응답을받는다
(developer를만든다) (아무 id나들어오면)->willreturn을 얻는다.
작동 구조 : developerdetailget을 하면 -> findbyid로 찾는다(이때 developer return).
mock을 통해 가짜로 생성되었기 떄문에, 이때 내가 만든 developer가 생성되어 들어간다 .
그후에 getdeveloperdetail에서 fromentity를써서 바꾼다.
그후 같은지 비교!
*service test 추가
객체 등을 선택해서, 캡쳐하는 객체를 생성한 것.
해당 captor라는 객체안의 값을 가져와서, 객체를 검증하고 기타 등등을 할 수 있다.
**SERVICE 추가 2
DUPLICATE시 , 예외 발생을 하기로 했었다.
해당 ERRORCODE가 잘 발생했나 확인하고 해당 EXCEPTION의 VALUE(ERRORCODE)가 우리가 설정한 ENUM이 되는지를 잘 확인해봊 ㅏ
Controller를 테스트해보자 .
-> @WebMvcTest(DMakerController.class) -> 특정 class를 빈에 올려줌.
사용. //web에서처럼 post, get을 해야되기 떄문에.
@Autowired
private MockMvc mockmvc ;
-> paramater들의 호출을 가상으로 생성하는, mvc가 제공하는 것
이와 같이, 사용할(json형태로 request body받기 떄문에)
type을 미리 지정해준다.
mockmvc는,get으로 해당 url로받아서/ contentype을맞춰준다.
그이후에 json경로에 따른 값이, is임을 기대한다// andexpect는 계속붙일수있다.
중간에
andDo(print())하면 쉽게 내용을 볼 수 있다!
MockMvc 예시 2
해당 문맥을 해석하면
MockMvc가, get (/note)인 척을 한다. 그리고 기대한다. httpstatus는 문제가 없고. 그리고 기대한다.
나온 view의 이름은 note/index인 것을. 모두 문제가 없다면 그것을 출력한다.
and Expect는, 해당 기대를 충족하지 않는다면 exception을 throw 한다.
모든 jpa가 뜨지 않아서 문제가 있었다.
config용 파일을 하나 생성해줘야한다!
COFING PACK-> 안의
AUDITING이 뭔데?
아까 가입과 로그아웃 시간을 위해 사용했던 ANNOTATION이 문제였다.
1. @EnableJpaAuditing
이게 MAIN에 있어서 안되었다.
일단은 이것을 제거하고, 별개의 CONFIG파일을 생성하여.
해당 CONFIG파일을 통해서 실행되는 경우만 AUDITING이 되게끔 하였다.
코딩을하다보면 아예알수없는 오류가발생한다. 이는 검색 하자.
++ 객체를 mock으로 생성하기
이와 같이 사용한다. PlayerDto 객체를, mock으로 생성하였다.
그 player의 get birthyear가 호출되면, 1980이라는 값을 return하게 조정한 것.
그후 결과를 넣고 예측한 값이 잘 나오나 확인한다.
-> 그러나 부족한 점이 있다. 1980이라는 값이 항상 동일하게 1980이 아니라 1981 , 1982등이 있을 수 있기 때문이다.
test는 언제 돌려도 동일해야한다. (실제 method의 변화에 따라 변화되면 안된다)
year.now()가 자동으로 진행되기 때문에, 이에 따라서 test의 결과가 바뀐다.
mockedstatic으로, year class를 static하게 생성한다.
그 이후 year class 또한 mock으로 생성한다.
그 mockyear에서 값을 가져올때, 2021을 return하게 하며, 그 mockyear에서 year의 now가 호출되면, 우리가만든 mockyear(2021이 들어가는객체)를 return한다.
이로써, salary의 게산시 year.now에 영향받지 않고 , 그 값의 변화까지 test할 수 있게 되었다.
--정리 --
SERVICE는 MOCK을 활용하여 가상의 객체를 만들고,
코드를 따라가 보며 GIVEN으로 특정 값을 주어준다.
그 값에 맞춰 잘 동작하나 확인하다
CONTROLLER는 이제 REQUEST를 받아내는 곳이기 떄문에, MOCKMVC를 활용하고
JSON TYPE을 임의로 생성하여 해당 TYPE에 맞춰서 ANDEXPECT로 값이 잘 맞는지를 확인한다.