ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [Junit] Test Double
    프로그래밍/Junit 2022. 2. 8. 01:37
    반응형

    이 글은 혼자 학습한 내용을 바탕으로 작성되었습니다.

    틀리거나 잘못된 정보가 있을 수 있습니다.

    댓글로 알려주시면 수정하도록 하겠습니다.


     

    1. Test Double

    테스트 더블(Test Double)은 제라드 메스자로스에 의해서 탄생한 단어로 테스트 자동화 과정에서 테스트 진행이 어려운 경우 이를 대신하여 테스트 진행이 가능하도록 만들어 주는 객체를 말합니다.

     

    Test Double은 큰 의미에서 테스트 진행이 가능하도록 만들어주는 객체를 말하며 아래 5가지의 세부 종류로 나눌 수 있습니다.

     

    Test Double 종류

    • Test Spy
    • Mock
    • Dummy Object
    • Test Stub
    • Fake Object

     

    2. Test Spy

    Test Stub 처럼 실제 동작을 수행하는 것이 아닌 미리 준비해둔 결과가 반환되도록 할 수 있습니다.

     

    Test Stub과 다른 점은 바로 특정 메소드에 대해서만 미리 준비한 결과가 반환되록 할 수 있습니다.

     

    MemberService Class
    Spy Test Class

    MemberService 클래스를 Spy 객체로 만들고 MemberService 객체가 필요한 MemberRepository 또한 Mock 객체로 만들어 MemberService에 주입하였습니다.

     

    이제 Mockito 프레임워크를 이용하여 MemberRepository의 findById 메소드를 수행 하였을때 결과와 MemberService의 encode메소드가 수행 되었을때 결과를 명세하여 MemberService의 encodeName 메소드 수행 하여 해당 결과를 비교하는 Test를 작성 하였습니다.

     

    Spy경우 특정 메소드만 결과 명세가 가능 하므로 MemberService의 encode메소드의 결과를 미리 명세한 뒤encodeName 메소드를 수행 하여 encodeName 메소드를 쉽게 Test 할 수 있습니다.

     

    3. Mock

    Test 하고자 하는 Class에서 사용하거나 참조하는 객체를 Mock객체로 만들고 해당 Mock객체의 특정 동작 호출 시 해당 결과를 명세하고 명세에 따라 동작하도록 만든 객체를 말합니다.

     

    예를 들어 MemberService는 Repository를 통해 Member를 조회하고 조회된 Member의 이름 뒤에 '님'을 붙이는 동작을 수행하도록 구현하였습니다.

     

    그럼 Service는 Repository의 findById 메소드를 통해 DB에 접속하여 특정 쿼리를 수행하고 결과로 반환된 Member의 이름 뒤에 '님'을 붙이는 동작을 수행할 것입니다.

     

    그러나 Mock 객체를 만들어 findById 메소드를 호출할 경우 해당 메소드의 결과를 직접 명세하여 해당 결과가 반환되도록 하고 다음 작업인 이름 뒤에 '님'을 붙이는 작업을 수행하도록 할 수 있습니다.

     

    MemberService Class
    Mock Test Class

    이번 Test의 경우 Mockito 프레임워크를 사용하므로 Extension을 사용 가능하도록 @ExtendWith를 적용합니다.

     

    이후 mock메소드를 통해 MemberRepository를 mock 객체로 만들고 해당 mock MemberRepository를 MemberService에 주입하여 MemberService 객체를 생성합니다.

     

    이후 given 메소드를 이용하여 Repository의 findById메소드가 호출되면 어떤 결과를 반환할지 willReturn 메소드에 명세합니다.

     

    이후 MemberService의 appendSir메소드 호출 시 MemberRepository의 findById를 호출하게 되고 이는 미리 선언한 결과를 반환하여 '홍길동'이름 뒤에 '님'을 붙여 '홍길동 님'을 반환할 것입니다.

     

    4. Dummy Object

    이름에서 알 수 있듯이 Dummy 객체를 의미하며 객체는 필요하지만 해당 객체의 동작(기능)은 필요하지 않은 경우에 사용하는 Test Double입니다.

     

    동작(기능)이 필요하지 않은 경우에 사용되므로 정상적인 동작이 보장되지 않습니다.

     

    MailService class

     

    MailSender Interface

    예를 들어 메일을 관련 작업을 하는 MailService가 있고 실제 Mail의 전송을 명세한 MailSender 인터페이스가 정의되어 있고 운영에 사용되는 MailSender 구현체는 실제 메일을 전송하도록 구현하였습니다.

     

    하지만 Test에서는 메일을 전송할 이유가 없어 MailSender의 Send 메소드의 동작이 필요 없습니다.

     

    MailService Test

    그래서 Serivce의 객체를 만들기 위해 생성자로 전달되는 MailSender 구현체를 Dummy Object로 전달하여 실제 메일을 전달하지 않는 MailService를 생성할 수 있습니다.

     

    5. Test Stub

    Test Stub은 Dummy와 유사합니다.

     

    Dummy의 경우 동작이 필요 없어 동작이 없지만 Test Stub의 경우 Dummy와는 다르게 동작이 가능한 것처럼 만들어 놓은 객체입니다.

     

    실제 동작을 수행하는 것이 아닌 미리 준비해둔 결과가 반환되도록 하는 것입니다.

     

    예를 들어 List <Member>에서 0번째 Index의 값을 get 하면 '홍길동'이라는 이름을 가진 Member가 반환되도록 하는 것입니다.

     

    TestStubList

    List 인터페이스를 구현한 TestStubList Class를 만들어 get 메소드 호출 시 Parameter로 전달받은 index의 값이 0인 경우 이름이 홍길동인 Member객체를 반환하도록 Stub을 작성하였습니다.

     

    TestSubList Test

    testStubList 객체를 생성하고 get 메소드의 Parameter로 0을 전달하여 이름이 홍길동인 Member 객체를 반환하는 것을 확인할 수 있습니다.

     

    해당 Test를 보면 List에 Member를 추가하지 않았지만 미리 준비해둔 결과에 의해 이름이 홍길동인 Member가 반환되는 것을 확인할 수 있습니다.

     

    Stub으로 사용할 Class를 신규로 작성하지 않고 Stub을 사용할 수 있도록 Mockito 프레임워크를 사용할 수 있습니다.

     

    Mockito Stub

    위처럼 List의 Mock을 만든 뒤 when 메소드를 통해 mock의 특정 메소드를 수행 시 thenReturn의 파라미터로 전달한 결과가 반환되도록 할 수 있습니다.

     

    6. Fake Object

    객체의 동작이 복잡한 경우 또는 내부에서 필요로 하는 외부 객체의 동작이 복잡한 경우 복잡한 동작을 단순화하여 구현한 Test Double입니다.

     

    즉 복잡한 로직을 통해 결과가 도출되는 실제 객체는 아니지만 특정 입력(Parameter)을 받아 단순화한 로직을 통해 출력(return Value)의 동작을 수행하는 객체를 말합니다.

     

    예를 들어 JPA를 사용하면 Repository를 통해 DB에 접속하여 데이터를 입력하고 조회할 수 있습니다.

     

    만약 Repository를 Test에 사용하게 된다면 DB에 Connection과 Test에 사용된 데이터가 쌓이게 되므로 Fake Object를 이용해 DB 접속과 같은 복잡한 과정을 제거하고 단순히 InMemory를 통해 쉽게 Test가 가능합니다.

     

    MemberRepository
    MemberService
    Test의 Inner Class로 생성한 Fake Repository

    Test의 Inner Class로 생성한 Fake Object를 통해 직접 DB로부터 데이터를 추가하거나 조회하는 것이 아닌 Collection인 Map을 이용하여 DB에 데이터를 저장하거나 조회하는 것과 유사하게 만들어 Test가 가능하도록 할 수 있습니다.

     

    사용된 예제 코드는 Git에 있습니다.

    반응형

    '프로그래밍 > Junit' 카테고리의 다른 글

    [Junit] doReturn과 thenReturn  (0) 2022.02.21
    [Junit] Test Double Spy 상세  (1) 2022.02.14
    [Junit] Mock과 MockBean  (0) 2022.02.12
    [Junit] Junit5 Exception Throw 테스트  (0) 2021.12.28

    댓글

Designed by Tistory.