발단
-
어느 날과 다름없이 비즈니스 로직을 먼저 작성하고 테스트 코드를 작성하는 코드 몽키 ing 중 🐒
-
테스트 코드 실행 전 초기 설정이 필요하여 Junit5의 @BeforeEach 사용
-
호기심이 발동하여 접근 지정자 private 지정
-
실행
-
어? 성공하네?
-
사용해도 되는건가? 공식 문서ㄱㄱ
@BeforeEach methods must have a void return type, must not be private, and must not be static.
-
private을 절대 사용하지 말라고 must로 명시되어져 있는데 왜 동작하는 거지? 🤔
-
구글링을 하였지만 명확한 답변을 찾을 수 없음
-
그래서 직접 삽질 시작 💀
동작하는 이유
결국 역시나 답은 Reflection 🤮
결론을 이미 부제에 달았지만 혹시나가 역시나 답은 리플렉션
디버깅을 걸어보자!
@BeforeEach 메서드 내부에 breakpoint 지정
Call Stack 중 눈에띄는 relfect!
하나 씩 거슬러 올라가다 의심 부근 발견!
- RelectionUtils.invokeMethod()
- RelectionUtils.makeAccessible()
여기서 object는 Method 객체, 더 정확히 말하자면 @BeforeEach가 달린 setUp() 메서드
Java Reflection에서는 전지전능 한 기능을 제공하고, 그중 private method를 접근할 수 있게 만들어버리는 매직(magic)을 제공 한다
자세한 내용은 문서 참고
심증은 찾았으니 물증 확인
해당 부분에 Breakpoint를 걸고 다시 디버깅
AccessibleObject.setAccessible() 에 의하여 변경되는 값은 결국 override
RelectionUtils.makeAccessible() 호출 전 override의 상태는 false!
이 상태에서는 private 지정자의 역할이 발휘된다
호출 이후 값을 확인해보면 true로 변경될 것을 확인할 수 있다
결론
Junit5에서 제공하는 @BeforeEach 어노테이션은 접근 지정자가 private이 되지 않기를 권고한다. 하지만 private을 지정해도 잘 돌아간다. 그 이유는 리플렉션을 사용하여 다 접근 가능하게끔 변경하기 때문이다. 고로 리플렉션은 깡패... 👹
'자바 개발자되기' 카테고리의 다른 글
자바 원시(Primitive) 타입과 참조(Reference) 타입, 그리고 Reflection (1) | 2021.01.01 |
---|---|
Spring @Transactional 어노테이션은 왜 Bean이 아닌 객체에서 적용되지 않는가? (0) | 2020.12.31 |
Junit5 - @BeforeEach @BeforeAll (0) | 2020.12.23 |
[우아콘2020] - Zero Payload 방식 리뷰 (0) | 2020.12.19 |
리팩토링과 TDD (0) | 2020.12.19 |