2016-08-10 7 views
1

私はSpringブートアプリケーション経由でAutowired @Serviceを期待通りに使用するRest Controller PUTメソッドを実行できます。 Spring JUnitテストを実行しようとしているときに同じAutowiringが失敗しています。私は同様の問題を持つ複数のスレッドを介して読んでみました。私は "新しい"キーワードを使って@Serviceを作成していないことを確認しました。私はContext Configurationと他のメソッドを試しました..しかし、すべて無駄であるようです。私はどこに間違っているのか分からない。Springテストサービスnullの結果のオートワイヤリング

私の春ブーツApplicationクラス -

@SpringBootApplication  
@ComponentScan({  
     "com.initech.myapp.*"  
     })  
public class IngestionServerApplication {  

    private static final Log logger = LogFactory.getLog(IngestionServerApplication.class);  

    public static void main(String[] args) {  
     SpringApplication.run(IngestionServerApplication.class, args);  
     logger.info("Ingestion Server Application started...");  
    }  
} 

休憩コントローラクラス -

package com.initech.myapp.ingestion.controller; 

@RestController 
public class IngestionController extends BaseRestController { 

    private static final Log logger = LogFactory.getLog(IngestionController.class); 

    // This variable is getting "null" autowiring if invoked 
    // via Spring Unit Testing framework while it is injected fine via 
    // Spring Boot app invocation. 
    @Autowired 
    public IngestionPayloadProcessor payloadProcessor; 

    @RequestMapping(path = "/ingest", method = RequestMethod.PUT, 
      consumes = { 
        MediaType.APPLICATION_JSON_VALUE, 
        MediaType.APPLICATION_XML_VALUE 
      }, 
      produces = { 
        MediaType.APPLICATION_JSON_VALUE 
      }) 
    public IngestionSuccessResponse ingest(@RequestHeader(value = "authToken", required = true) String authToken,       
         @RequestBody String jsonBody) throws Exception { 

     IngestionPayload ingestionPayload = new IngestionPayload(); 
     ingestionPayload.setAuthToken(authToken); 
     ingestionPayload.setJsonBody(jsonBody); 

     IngestionSuccessResponse ingestionSuccessResponse = payloadProcessor.process(ingestionPayload); 

     return ingestionSuccessResponse; 
    } 
} 

サービスクラス

package com.initech.myapp.ingestion.app.service; 

@Service 
@ImportResource({"spring.xml"}) 
public class IngestionPayloadProcessor { 

    private static final Log logger = LogFactory.getLog(IngestionPayloadProcessor.class); 

    @Resource(name = "kafkaConfig") 
     private Properties kafkaConfig; 

    @Value("${kakfaTopic}") 
     private String kakfaTopic; 

    public IngestionSuccessResponse process(IngestionPayload ingestionPayload) throws Exception { 
      try { 

      IngestionSuccessResponse ingestionSuccessResponse = buildSuccessResponse(ingestionPayload); 

      return ingestionSuccessResponse; 
        } 
       catch (IllegalStateException e) 
       { 
        logger.error("Encountered exception while dropping message in Kafka... " + e.getMessage()); 
         throw e; 
        } 
      } 
      } 

private buildSuccessResponse() { ... } 

春ユニットテスト

@RunWith(SpringRunner.class) 
@ContextConfiguration(locations = "classpath*:/spring.xml") 
@WebMvcTest(IngestionServerApplication.class) 
public class IngestionServerApplicationTests { 
    @Autowired 
    private MockMvc mockMvc; 

    @Before 
    public void setUp() throws Exception { 
     mockMvc = MockMvcBuilders.standaloneSetup(
        new IngestionServiceController()) 
          .build(); 
       } 

    @Test 
    public void testIngestService() throws Exception { 

     HttpHeaders httpHeaders = new HttpHeaders(); 
       httpHeaders.add("authToken","safdafio12312asdfs23"); 
       RequestBuilder requestBuilder = put("/ingest").content("{'testKey' : 'testVal'}").accept(MediaType.APPLICATION_JSON).headers(httpHeaders); 

     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()); 
    } 
} 

エラーログ

2016-08-10 19:24:36.500 DEBUG 7505 --- [   main] m.m.a.RequestResponseBodyMethodProcessor : Read [class java.lang.String] as "application/json" with [[email protected]aa766b] 
2016-08-10 19:24:36.510 DEBUG 7505 --- [   main] .m.m.a.ExceptionHandlerExceptionResolver : Resolving exception from handler [public com.initech.myapp.ingestion.model.IngestionSuccessResponse com.initech.myapp.ingestion.app.controller.myappIngestionServiceController.ingest(java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String,java.lang.String) throws java.lang.Exception]: java.lang.NullPointerException 
2016-08-10 19:24:36.512 DEBUG 7505 --- [   main] .m.m.a.ExceptionHandlerExceptionResolver : Invoking @ExceptionHandler method: public org.springframework.http.ResponseEntity<java.util.Map<java.lang.String, java.lang.Object>> com.initech.myapp.base.controller.BaseRestController.handleException(java.lang.Exception,javax.servlet.http.HttpServletRequest) 
This is the error handler... 
2016-08-10 19:24:36.514 INFO 7505 --- [   main] p.d.i.a.c.myappIngestionServiceController : > handleNoResultException 
2016-08-10 19:24:36.574 DEBUG 7505 --- [   main] o.s.w.s.m.m.a.HttpEntityMethodProcessor : Written [{status=500, authToken=6acb1a5c-2ced-4690-95b3-eb7957c7c28a, error=null}] as "application/json" using [org.springframework.http.converter.json.Ma[email protected]] 

java.lang.AssertionError: Status 
Expected :200 
Actual :500 

私はテストを通じてデバッグしていると私はpayloadProcessorオブジェクトがnullであるようにNullPointer例外が残りコントローラクラスで以下の行でスローされることがわかります注意。

IngestionSuccessResponse ingestionSuccessResponse = payloadProcessor.process(ingestionPayload); 

モックオブジェクトと=====

単体テスト:(これは期待通りに動作している)

@RunWith(SpringRunner.class) 
@ActiveProfiles("dev") 
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) 
@AutoConfigureMockMvc 
public class IngestionServerUnitTests { 

    @Autowired 
    private MockMvc mockMvc; 

    @MockBean 
    private IngestionPayloadProcessor processor; 

    // I was able to get this to work by removing the setUp() method 
    // that was originally in my code. It was trying to build a new instance 
    // of the REST controller and then run the "perform" on top of it 
    // which was causing the test to fail I assume! 

    /*@Before 
    public void setUp() throws Exception { 
     mockMvc = MockMvcBuilders.standaloneSetup(
       new IngestionServiceController()) 
       .build(); 
    }*/ 

    @Test 
    public void testIngestService() throws Exception { 

     IngestionSuccessResponse ingestionSuccessResponse = new IngestionSuccessResponse(); 
     ingestionSuccessResponse.setStatusCode("200"); 
     ingestionSuccessResponse.setRequestId("6acb1a5c-2ced-4690-95b3-eb7957c7c28a"); 
     ingestionSuccessResponse.setReceivedTimestamp("2016-08-09T19:43:30.02234312"); 

     given(this.processor.process(anyObject())).willReturn(ingestionSuccessResponse); 

     HttpHeaders httpHeaders = new HttpHeaders(); 
     httpHeaders.add("Authorization","5e18685c95b34690"); 

     RequestBuilder requestBuilder = put("/ingest").content("<test>test data</test>").accept(MediaType.APPLICATION_JSON).headers(httpHeaders); 

     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()); 
    } 

} 
+0

テストを実行しようとするとスローされるエラー/例外を提供できますか? –

+0

Mock、MockBeanのいずれかを使用する方法の詳細については、このリンク「https://stackoverflow.com/questions/44200720/difference-between-mock-mockbean-and-mockito-mock」を使用してください。 –

答えて

6

あなたが@WebMvcTestを指定すると、アプリケーションの唯一の特定のコンポーネントがありますそれらはApplicationContextに追加されます。この注釈は、実際にはドキュメントに記述されているような他の注釈の構成です。IngestionPayloadProcessorはBeanとしてインスタンス化されず、テストのみを実行するように指示してはいけません。ウェブ層のテスト。あなたがする必要があるのは、テスト内でIngestionPayloadProcessor@MockBeanを指定し、コントローラが呼び出しているメソッドのモックを定義することです。春ブーツ1.4テストの新機能の

@RunWith(SpringRunner.class) 
@WebMvcTest(IngestionServerApplication.class) 
public class IngestionServerApplicationTests { 
    @Autowired 
    private MockMvc mockMvc; 

    @MockBean 
    private IngestionPayloadProcessor processor; 

    @Test 
    public void testIngestService() throws Exception { 
     given(this.processor.process(anyObject())).willReturn(new InjestionSuccessResponse()); 

     HttpHeaders httpHeaders = new HttpHeaders(); 
     httpHeaders.add("authToken","safdafio12312asdfs23"); 
     RequestBuilder requestBuilder = put("/ingest").content("{'testKey' : 'testVal'}").accept(MediaType.APPLICATION_JSON).headers(httpHeaders); 

     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()); 
    } 
} 

詳細はこちらです:https://spring.io/blog/2016/04/15/testing-improvements-in-spring-boot-1-4

*コメントに基づいて更新*

あなただけの自動MockMvc設定および使用する必要はありませんでした実現TestRestTemplate。私はこれをテストしていないが、うまくいくはずです。

@RunWith(SpringRunner.class) 
@SpringBootTest 
@AutoConfigureMockMvc 
public class IngestionServerApplicationTests { 
    @Autowired 
    private MockMvc mockMvc; 

    @Test 
    public void testIngestService() throws Exception { 
     HttpHeaders httpHeaders = new HttpHeaders(); 
     httpHeaders.add("authToken","safdafio12312asdfs23"); 
     RequestBuilder requestBuilder = put("/ingest").content("{'testKey' : 'testVal'}").accept(MediaType.APPLICATION_JSON).headers(httpHeaders); 

     this.mockMvc.perform(requestBuilder).andExpect(status().isOk()); 
    } 
} 
+0

@ shawn-larkこれはモックの代わりに実際のオブジェクトを介して行うことができる方法はありますか? WebMvcTestアノテーションを変更する必要がある場合は、変更することができます。助言がありますか? – Satya

+0

フレームワークのスライスではなく、統合レベルのテストを本当にしたいと思うようです。この場合、@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)アノテーションを使用する必要があります。それはあなたがテストできるようにアプリケーションを立ち上げます。 '@Autowired TestRestTemplate'を実行して、あなたがサービスを呼び出す外部クライアントであるかのように呼び出しを行うことができます。 –

+2

私の答えを更新しました...入力中に特定の '@WebMvcTest'を使わずにテストでMockMvcを使うことができることを理解しました –

関連する問題