56901


### 前提・実現したいこと

JpaRepository.saveAndFlush()でExceptionが発生した場合のテストを行うためmockit.doThrow()を使用しています。

テストを行いたいメソッド内部でsaveAndFlush()の対象entityのインスタンス作成を行っている場合、saveAndFlush()戻り値がnullとなりExceptionが発生しませんでした。

しかし、saveAndFlush()の対象entityをテストを行いたいメソッドの引数に指定しテストクラスからentityを渡した場合、期待通りExceptionが発生しました。

上記違いでなぜmockit.doThrow()のExceptionが発生しないのかわからないため、ご教授いただけないでしょうか。

### Exceptionが発生しないソースコード

[code]

    @Service
    @Transactional(readOnly = true)
    public class ServiceImpl implements Service
    {
        @Autowired
        private Repository _repository;
    
        @Override
        @Transactional(readOnly = false, rollbackFor = Exception.class)
        public boolean insert(String user) throws Exception
        {
            UserMst userMst = this.setUserMst(user);
            try
            {
                _repository.saveAndFlush(userMst);
            }catch(Exception e)
            {
                return false;
            }
            return true;
        }
    
        private UserMst setUserMst(String user)
        {
            UserMst userMst = new UserMst();
            userMst.setUserId(user);
            return userMst;
        }
    }
    
    
[/code]

[code]

    @RunWith(SpringRunner.class)
    @TestExecutionListeners({
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class
      })
    @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
    public class ServiceImplTest
    {
        @Mock
        private Repository rep;
    
        @InjectMocks
        private ServiceImpl service;
    
        @Test
        public void testInsertError01()
        {
            boolean actual = false;
            try
            {
                // TODO:throwされない
                doThrow(new NullPointerException()).when(rep).saveAndFlush(new UserMst());
                actual = service.insert("user");
            }catch(Exception e)
            {
            }
            assertThat(actual).isEqualTo(false); // 結果がtrueとなるためNG
        }
    }
    
    
[/code]

### Exceptionが発生したソースコード

[code]

    @Service
    @Transactional(readOnly = true)
    public class ServiceImpl implements Service
    {
        @Autowired
        private Repository _repository;
    
        @Override
        @Transactional(readOnly = false, rollbackFor = Exception.class)
        public boolean insert(UserMst userMst) throws Exception
        {
            userMst.setUserId(user);
            try
            {
                _repository.saveAndFlush(userMst);
            }catch(Exception e)
            {
                return false;
            }
            return true;
        }
    }
    
    
[/code]

[code]

    @RunWith(SpringRunner.class)
    @TestExecutionListeners({
        DependencyInjectionTestExecutionListener.class,
        DirtiesContextTestExecutionListener.class
      })
    @DirtiesContext(classMode = DirtiesContext.ClassMode.AFTER_EACH_TEST_METHOD)
    public class ServiceImplTest
    {
        @Mock
        private Repository rep;
    
        @InjectMocks
        private ServiceImpl service;
    
        @Test
        public void testInsertError01()
        {
            UserMst userMst = new UserMst();
            boolean actual = false;
            try
            {
                // TODO:throwされた
                doThrow(new NullPointerException()).when(rep).saveAndFlush(userMst);
                actual = service.insert(userMst);
            }catch(Exception e)
            {
            }
            assertThat(actual).isEqualTo(false); // 結果がfalseでOK
        }
    }
    
    
[/code]

上記質問はteratailでも投稿しています。  
<https://teratail.com/questions/202524>  
※teratailで回答・解決があった場合は、stackoverflowにも記載します。


CC BY-SA 4.0
2019-07-25T12:30:19.097
56891
2019-07-26T05:33:23.407
2019-07-26T05:33:23.407
35256
35256
question
java spring-boot jpa mockito
Junit+SpringBoot+JpaRepository.saveAndFlush()でmockit.doThrow()を指定してもExceptionが発生しない

[code]

        doThrow(new NullPointerException()).when(rep).saveAndFlush(new UserMst());
    
[/code]

の意味するところは、`rep`の`saveAndFlush`メソッドを指定したオブジェクトを引数に伴って呼び出した場合に
`NulPointerException`を送出する、です。  
例外を送出するには引数のオブジェクトも同じである必要があります。

質問文中のコードでは、

[code]

    // TODO:throwされない
    doThrow(new NullPointerException()).when(rep).saveAndFlush(new UserMst());
    
[/code]

で指定している **`new UserMst()`** と、テスト対象である `ServiceImpl#insert` メソッド

[code]

            _repository.saveAndFlush(userMst);
    
[/code]

で指定している **`userMst`** が同じではないので例外を送出する条件に当てはまっていません。

ここで、"同じである"かどうかは、[デフォルトでは`equals`を用いて評価されます](https://static.javadoc.io/org.mockito/mockito-
core/3.0.0/org/mockito/Mockito.html#argument_matchers)。

メソッドが呼ばれたら引数が何であれ例外を送出したい、というのであれば
[`any()`](https://static.javadoc.io/org.mockito/mockito-
core/3.0.0/org/mockito/ArgumentMatchers.html#any--) が使えます。

[code]

    import static org.mockito.Mockito.any;
    ...
                doThrow(new NullPointerException()).when(rep).saveAndFlush(any());
                actual = service.insert("user");
    
[/code]


CC BY-SA 4.0
2019-07-26T02:56:18.243
56901
2019-07-26T02:56:18.243
2808
56891
answer