LinkedIn

Junit5 @BeforeEach private method가 동작하는 이유

2020. 12. 30. 13:59 | 자바 개발자되기

발단

  • 어느 날과 다름없이 비즈니스 로직을 먼저 작성하고 테스트 코드를 작성하는 코드 몽키 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을 지정해도 잘 돌아간다. 그 이유는 리플렉션을 사용하여 다 접근 가능하게끔 변경하기 때문이다. 고로 리플렉션은 깡패... 👹