0

Spring ブート gradle アプリで REST API をテストしています。@MockBean を使用してモックされたサービスが null を返しています。このモックされたサービスは、サービス クラスに Autowired の Bean がある場合に null を返します (コンストラクター インジェクションを使用しました)。

これがサンプルコードです(コンパイルされていません。理解のためだけです)


    @RestController
    @RequestMapping("/xxx")
    class TestController {

        private RetriveDataService retriveDataService;

        public TestControllerx(RetriveDataService retriveDataService) {
            this.retriveDataService = retriveDataService;
        }

        @PostMapping(value = "/yyy")
        public MyResponseModel myMethod(@RequestBody MyRequestModel model) {

            return retriveDataService.retriveData(model);
        }

    }

    @Service
    class RetriveDataService {

        private TokenService tokenService;

        public RetriveDataService(TokenService tokenService) {
            this.tokenService = tokenService;
        }

        public MyResponseModel retriveData(MyRequestModel model) {
            String accessToken = tokenService.getToken().getAccessToken();

            return retriveData(model, accessToken);
        }

    }

    @RunWith(SpringRunner.class)
    @WebMvcTest(TestController.class)
    public class TestControllerTest {

        @Autowired
        private MockMvc mvc;

        @Autowired
        private ObjectMapper objectMapper;

        @MockBean
        private RetriveDataService retriveDataService;

        @Test
        public void testRetriveData() throws Exception {

            mvc.perform(MockMvcRequestBuilders.post("/xxx/yyy").content(objectMapper.writeValueAsString(new MyRequestModel()))
                    .contentType(MediaType.APPLICATION_JSON_UTF8)).andDo(MockMvcResultHandlers.print())
                    .andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8));
        }

    }

このテストを実行すると、次の出力が得られます (サービスが別の Bean を必要としない場合、期待される出力が得られます)

MockHttpServletResponse:
           Status = 200
    Error message = null
          Headers = []
     Content type = null
             Body = 
    Forwarded URL = null
   Redirected URL = null
          Cookies = []

この応答により、.andExpect(content().contentType(MediaType.APPLICATION_JSON_UTF8)); という行で問題に直面しています。また、応答本文をチェックするとき(本文もnullであるため)

問題を再現するためのサンプル プロジェクトはこちら

4

1 に答える 1

0

リポジトリを確認すると、問題のコメントでの議論から仮定が確認されました。

モックで期待を指定します

MyModel requestMessage = new MyModel();
requestMessage.setMessage("Hello Request Post");
given(testService1.getMessage(requestMessage)).willReturn(responseMessage);

ただし、コントローラーで受信したメッセージは@WebMvcTest、テストで指定された requestMessage と同じではありません。これは、クラスがメソッドMyModelをオーバーライドしないためです。equalsこの状況では、Mockito はデフォルトの動作を使用します。

デフォルトでは、値を返すすべてのメソッドに対して、モックは必要に応じて null、プリミティブ/プリミティブ ラッパー値、または空のコレクションを返します。たとえば、int/Integer の場合は 0、boolean/Boolean の場合は false です。

問題を解決するには、次の 2 つのオプションがあります。

  1. リクエスト クラスでオーバーライドequals(および) します。hashCode
  2. 引数マッチャーについて理解する

オプション 2 の詳細:

技術的には、あなたの期待は次のものと同等です。

given(testService1.getMessage(ArgumentMatchers.eq(requestMessage)))
  .willReturn(responseMessage);

他のマッチャーを使用することも、独自に定義することもできます。これは、引数の型 (サード パーティ ライブラリからの型など) のコードを変更できない場合に便利です。たとえば、次のように使用できます。ArgumentMatchers.any(MyModel.class))

于 2019-09-19T08:01:20.903 に答える