ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Spring] Test에서 public이 아닌 필드 Reflection 으로 값 넣어주는 법
    Server/Spring 2021. 11. 26. 21:21
    728x90
    반응형

    Test에서 public이 아닌 필드를 Reflection 으로 값 넣어주는 법

    이번 글에서는 테스트 코드를 작성하면서 public이 아닌 필드에 값을 넣어주어야 하는 상황에서 Reflection을 사용해서 값을 넣어주는 법에 대해서 정리해보겠습니다. 이번 글은 Reflection이 무엇인지 설명하는 글은 아니다 보니 Reflection을 알고 싶다면 Reflection 알아보기 를 참고하시면 좋을 거 같습니다.

     

    먼저 제가 진행하고 있는 프로젝트에서 겪은 상황에 대해서 공유해보겠습니다.

    스크린샷 2021-11-26 오후 8 48 59

    현재 RepositoryMockito를 사용해서 Mocking 하고 Service Layer의 메소드만 Unit Test를 해보려 하고 있습니다. 내부 로직이 없고 단순히 Entity -> DTO로 변환하는 메소드 입니다.

     

    스크린샷 2021-11-26 오후 8 51 21

    DTO 내부를 보면 Post가 만들어진 시간인 LocalDate 타입의 createdAt을 클라이언트에게 반환해주어야 하는 상황입니다.

     

    스크린샷 2021-11-26 오후 8 48 13

    Post EntityJPA Auditing 기능을 사용하여 createdAt, updatedAt을 자동으로 만들어주는 기능을 사용하고 있습니다. 즉, Post EntityBaseEntity를 부모 클래스로 extends 하고 있는 것을 볼 수 있습니다.

     

    스크린샷 2021-11-26 오후 8 54 53

    createdTime의 접근 지정자를 보면 protected인 것을 볼 수 있습니다. private여도 마찬가지고 public이 아니라는 것을 알 수 있습니다. 이러한 상황에서 테스트 코드를 작성해보겠습니다.

     

    스크린샷 2021-11-26 오후 9 00 56

    위처럼 RepositoryMocking 하고(given) Service를 호출(when) 하였습니다. 문제 없이 잘 실행 되겠구나 했습니다.

     

    스크린샷 2021-11-26 오후 9 03 12

    NPE가 발생하는 것을 볼 수 있는데요. 원인은 찾아가보면 위의 DTO 클래스에서 Entity -> DTO 변환할 때 createdAt 값이 필요한데 제가 넣지 않아서 NPE가 발생하는 것입니다.

     

    스크린샷 2021-11-26 오후 9 04 36

    그래서 Post Entity를 만드는 createPost() 메소드에서 createdAt을 넣어주고 싶었지만 createdAt은 부모 클래스인 BaseEntity에 존재하기 때문에 값을 넣을 수 없는 문제가 발생했습니다.

     

    스크린샷 2021-11-26 오후 9 07 56

    그래서 위와 같이 값을 넣어주기 위해서 필드에 Setter 어노테이션을 만들었습니다.

     

    스크린샷 2021-11-26 오후 9 09 31

    그래서 위와 같이 setter를 사용해서 Post EntityLocalDateTime 값을 넣었습니다. 이렇게 해도 가능한 방법이지만 테스트 코드로 인해서 운영 코드에 Setter를 추가해야 하는 것이 맘에 들지 않았습니다. 그래서 이럴 때 사용할 수 있는 것이 ReflectionTestUtils 클래스 입니다.



    ReflectionTestUtils

    ReflectionTestUtils 를 보면 public이 아닌 필드를 리플랙션을 통해서 값을 넣어줄 수도 있고 private 메소드에게도 사용할 수 있고 기능은 여러가지가 있는 것 같습니다. 하지만 이렇게 Superclacss의 필드를 어떻게 값을 넣는지 찾기가 쉽지 않았습니다.

     

    스크린샷 2021-11-26 오후 9 14 41

    해결 방법은 setField를 사용하여 값을 넣는 것인데요. 매개 변수를 잘 넘겨주어야 합니다.

     

    1. 자식 클래스 객체 (getClass 아님)
    2. 부모 클래스.class
    3. 부모 클래스에서 set Reflection 할 필드 이름
    4. 필드 타입의 값 (현재라면 LocalDateTime)
    5. 필드 타입.class

     

    위처럼 5개의 매개변수를 넘기면 Post EntitycreatedAt 필드의 값을 Reflection으로 넣을 수 있습니다.

     

    스크린샷 2021-11-26 오후 9 17 33

    그리고 테스트를 실행하면 문제 없이 테스트가 성공하는 것을 볼 수 있습니다.

    반응형

    댓글

Designed by Tistory.