Mockito 2の使用


1.Mockオブジェクトの確認


1-1. 特定のメソッドの動作と呼び出し回数の決定

  • Mockitoのverify()メソッドにより、特定のメソッドが何回実行されたかを決定できます.
  • public class StudyService {
    
    		public Study createNewStudy(Long memberId, Study study) {
            Optional<Member> member = memberService.findById(memberId);
            study.setOwnerId(memberId);
    
            Study newStudy = repository.save(study);
            //memberService.notify(newStudy);
            return repository.save(study);
        }
    
    		...
    }
    @ExtendWith(MockitoExtension.class)
    class StudyServiceTest {
    
    		@Test
        void stubbing(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
            StudyService studyService = new StudyService(memberService, studyRepository);
            assertNotNull(studyService);
    
            Member member = new Member();
            member.setId(1L);
            member.setEmail("[email protected]");
    
            Study study = new Study(10, "테스트");
    
            Mockito.when(memberService.findById(1L)).thenReturn(Optional.of(member));
            Mockito.when(studyRepository.save(study)).thenReturn(study);
    
            studyService.createNewStudy(1L, study);
    
            assertNotNull(study.getOwnerId());
            assertEquals(member.getId(), study.getOwnerId());
    
            Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
            Mockito.verify(memberService, Mockito.never()).validate(Mockito.any()); // validate 메서드는 호출되지 않길 기대
        }
    }

  • テストコードの最後の行ではmemberServiceのnotify()メソッドが1回呼び出されることを期待したが,コメント処理が完了したためnotify()メソッドは動作せず,エラーが発生した.

  • また、never()メソッドを使用して、メソッドが呼び出されていないかどうかを確認することもできます.
  • 1-2. コール順序の確認

    public class StudyService {
        private final MemberService memberService;
        private final StudyRepository repository;
    
        ...
    
        public Study createNewStudy(Long memberId, Study study) {
            Optional<Member> member = memberService.findById(memberId);
            study.setOwnerId(memberId);
    
            Study newStudy = repository.save(study);
            memberService.notify(newStudy);
            memberService.notify(member.get());
            return repository.save(study);
        }
    }
    notify()メソッドを呼び出して
  • 新しい学習器を作成し、メンバーに通知するnotify()メソッド
  • を呼び出します.
    @ExtendWith(MockitoExtension.class)
    class StudyServiceTest {
    		@Test
        void stubbing(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
            ...
    
            InOrder inOrder = Mockito.inOrder(memberService);
    
    	//성공
            inOrder.verify(memberService).notify(study);
            inOrder.verify(memberService).notify(member);
    
    	//실패
    	inOrder.verify(memberService).notify(member);
            inOrder.verify(memberService).notify(study);
        }
    
    }
    まず
  • Inorderを作成します.
    実際に呼び出されたメソッドの順序でverify()を行うと、テストは成功します.
  • 1-3. ある時点で何も起こらなかったことを確認します

  • すなわち、特定のメソッドが呼び出された後に、メソッドが呼び出されていないと判断することができる.
  • public class StudyService {
        private final MemberService memberService;
        private final StudyRepository repository;
    
    		...
    
        public Study createNewStudy(Long memberId, Study study) {
            Optional<Member> member = memberService.findById(memberId);
            study.setOwnerId(memberId);
    
            Study newStudy = repository.save(study);
            memberService.notify(newStudy);
            memberService.notify(member.get());
            return repository.save(study);
        }
    }
    @ExtendWith(MockitoExtension.class)
    class StudyServiceTest {
    		@Test
        void stubbing(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
            ...
    
    	//실패
            Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
    	Mockito.verifyNoMoreInteractions(memberService); // 실패 아래 notify()메서드가 동작하므로
            Mockito.verify(memberService, Mockito.times(1)).notify(member); // notify 메서드가 한번 호출하기를 기대
            
    	//성공
    	Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
            Mockito.verify(memberService, Mockito.times(1)).notify(member); // notify 메서드가 한번 호출하기를 기대
    	Mockito.verifyNoMoreInteractions(memberService);
        }
    
    }
  • VerifyNoMoreInteraction()メソッドを使用すればよい.
  • 2.Mockito BDDスタイルAPI


    2-1. BDD

  • BDDとは?
  • 行動駆動開発、行動主導開発だそうです.TDDは、アプリケーションがどのように行動すべきかについての共通認識を作成しました.
  • 行動の仕様
  • 国/地域(行動説明を定義する場合)
  • As a/i want/so that
  • Acceptance criteria
  • Given/When/Then
  • は、ある状況が発生したとき/ある行動を取ったとき/このような結果が現れるべきである.
  • 2-2. BDDスタイルAPIの適用

    @ExtendWith(MockitoExtension.class)
    class StudyServiceTest {
    		@Test
        void stubbing(@Mock MemberService memberService, @Mock StudyRepository studyRepository) {
            //Given
            StudyService studyService = new StudyService(memberService, studyRepository);
            assertNotNull(studyService);
    
            Member member = new Member();
            member.setId(1L);
            member.setEmail("[email protected]");
    
            Study study = new Study(10, "테스트");
    
            Mockito.when(memberService.findById(1L)).thenReturn(Optional.of(member));
            Mockito.when(studyRepository.save(study)).thenReturn(study);
    
            //when
            studyService.createNewStudy(1L, study);
    
            //then
            Mockito.verify(memberService, Mockito.times(1)).notify(study); // notify 메서드가 한번 호출하기를 기대
            Mockito.verify(memberService, Mockito.times(1)).notify(member); // notify 메서드가 한번 호출하기를 기대
            Mockito.verify(memberService, Mockito.never()).validate(Mockito.any()); // validate 메서드는 호출되지 않길 기대
    
            Mockito.verifyNoMoreInteractions(memberService);
        }
    }

  • Given,When,Thenに分けることができます.

  • JBehaveなどのライブラリもサポートしていますが、使用する必要はありません.
    Mockitoは、BDにも対応しています.

  • 上から見るとMockito使用when()はGivenに相当するが、APIはwhenである.
    ちょっと調子が合わない.従って、when()の代わりにwhen()、then()の代わりにverify()などというAPIが提供される.
  • Ref

  • https://javadoc.io/doc/org.mockito/mockito-core/latest/org/mockito/Mockito.html
  • https://www.inflearn.com/course/the-java-application-test