2016-08-23 4 views
2

私は、いくつかのユニットテストに必要な依存関係を模擬するのにいくつかの困難を抱えています。私は、Mockitoの使用方法を正しく理解していないと思う。thenReturn()。ここで(methodX).thenReturn(resultY)の場合、methodXは呼び出されますか?

がある(うまくいけば、関連する)サービスのためのコードの一部は、私がテストしたい:

public class AppointmentServiceTest { 

    private UriInfo mockUriInfo; 
    private HttpResponse mockHttpResponse; 

    @Mock 
    private DataConnector mockDataConnector; 

    @InjectMocks 
    private AppointmentService appointmentService; 

    @Before 
    public void setUp() throws Exception { 
     MockitoAnnotations.initMocks(this); 
     mockUriInfo(); 
     mockHttpResponse(); 
    } 

    private void mockUriInfo() { 
     mockUriInfo = mock(UriInfo.class); 
     when(mockUriInfo.getRequestUri()).thenReturn(
      URI.create("http://localhost:8080")); 
    } 

    private void mockHttpResponse() { 
     mockHttpResponse = mock(HttpResponse.class); 
     when(mockHttpResponse.getInputStream()).thenReturn(
      IOUtils.toInputStream("{\"appointment\":{}}")); 
    } 

    @Test 
    public void testGetAppointment() throws Exception { 
     when(mockDataConnector.getAppointmentById(Mockito.anyString())). 
      thenReturn(mockHttpResponse); 
     when(appointmentService.validateResponse(Mockito.any(HttpResponse.class), Mockito.any(UriInfo.class))). 
      thenReturn(new Appointment()); 
     appointmentService.getAppointment(mockUriInfo, "12345"); 
     verify(mockDataConnector).getAppointment(Mockito.anyString()); 
    } 
} 

@Singleton 
public class AppointmentService { 
    private DataConnector connector; 

    @Inject 
    public AppointmentService(DataConnector connector) { 
     this.connector = connector; 
    } 

    public Appointment getAppointment(UriInfo uriInfo, String id) { 
     HttpResponse response = connector.getAppointment(id); 
     return validateResponse(response, uriInfo); 
    } 

    protected Appointment validateResponse(HttpResponse response, UriInfo uriInfo) { 
     try { 
      AppointmentWrapper appointmentWrapper = JacksonJsonUtility.readValue(response.getInputStream(), AppointmentWrapper.class); 
      if(appointmentWrapper.getAppointment()!=null) { 
       return appointmentConverterHelper(appointmentWrapper.getAppointment(), uriInfo.getPath()); 
      } 
     } catch(IOException e) { 
      throw new ResponseParsingException("IOException: " + e.getMessage()); 
     } 
    } 

    protected Appointment appointmentConverterHelper(ExternalAppointmentModel appointmentDto, String uriPath) { 
     if (appointmentDto == null) { 
      throw new BrickworkQueryException("Got an invalid appointment object from Brickwork!"); 
     } 

     Customer customer = new Customer(new Name(appointmentDto.getCustomer().getName()), 
      appointmentDto.getCustomer().getEmail(), 
      String.valueOf(appointmentDto.getCustomer().getCode())); 

     return new Appointment(
      appointmentDto.getId(), 
      customer); 
    } 

} 

私の理解では、この方法のための私のユニットテストは、次のようになりますということです

私のテストを実行すると、おそらく空である、appointmentDto.getCustomer()を呼び出そうとするときに、appointmentConverterHelperメソッドでNullPointerExceptionが発生します。コードが実行されているので、mockHttpResponseに完全に有効なAppointmentを含むInputStreamを返す必要があるようです。私はwhen(appointmentService.validateResponse(mockHttpResponse, mockUriInfo)).thenReturn(new Appointment());を持っているので、validateResponseコールを受け取り、実際にvalidateResponseを実行するのではなく、空のAppointmentオブジェクトを返してはいけませんか?

参照のため、ここでは、上記のwhenステートメントは、AppointmentServiceTestのException-line 140のスタックトレースです。私は問題がwhen文は、特定のインスタンスに対して一致しようとしていると失敗していることかもしれないと思う

java.lang.NullPointerException 
    at com.nike.appointmentservice.service.AppointmentsService.validatedResponse(AppointmentsService.java:176) 
    at com.nike.appointmentservice.service.AppointmentsServiceTest.testGetAppointmentById(AppointmentsServiceTest.java:140) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47) 
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12) 
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44) 
    at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17) 
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:26) 
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:271) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:70) 
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50) 
    at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238) 
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63) 
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236) 
    at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53) 
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229) 
    at org.junit.runners.ParentRunner.run(ParentRunner.java:309) 
    at org.junit.runner.JUnitCore.run(JUnitCore.java:160) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:119) 
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:42) 
    at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:234) 
    at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:74) 
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) 
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) 
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) 
    at java.lang.reflect.Method.invoke(Method.java:498) 
    at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)``` 
+0

NPEのスタックトレースを送信できますか? –

+0

@ Code-Apprenticeスタックトレースが追加されました – DanHam

答えて

3

:AppointmentsServiceのライン176は、validateResponse方法の非常に先頭にJacksonJsonUtility.readValue(response.getInputStream(), AppointmentWrapper.class);ラインです。 Mockitoユニットテストを開始するには、whenステートメントの特定の値を「何か」を表すMockitoプレースホルダに置き換える必要があります。例:

when(mockDataConnector.getAppointmentById(Mockito.anyString())). 
    thenReturn(mockHttpResponse); 

when(appointmentService.validateResponse(Mockito.any(HttpResponse.class), Mockito.any(UriInfo.class))). 
     thenReturn(new Appointment()); 

基本的な単体テストの作業が完了したら、より具体的な単体テストを追加できます。

更新

私は今あなたがAppointmentServiceクラスをテストしようとしているが、あなたはまた、そのクラス内のvalidateResponse方法をからかっていることに注意してください。私はこれが完全に間違っているかどうかを知るためにMockitoの専門家では不十分ですが、これは単体テストでMockitoを使用する方法ではありません。私がテストしているクラスはまったく嘲笑されていませんが、代わりに、それが呼び出すクラスを模擬して、さまざまな動作をシミュレートし、テストされたクラスがどのように応答するかを見ていきます。

JacksonJsonUtilityクラス(powermockは静的クラスで助けます)を模倣し、validateResponseメソッドのモックを削除する必要があると思います。 JacksonJsonUtility.readValueメソッドへの模擬応答を作成し、AppointmentServiceクラスが期待するすべてのものが含まれるようにする必要があります。

+0

この編集を行いましたが、validateResponseメソッド内でまだNullPointerExceptionが発生しているようです。それは、私がまだ何らかの形で特定のインスタンスと照合しようとしていることを意味すると思いますか? – DanHam

+0

実際の 'appointmentService.getAppointment'呼び出しをコメントアウトしても例外がvalidateResponse' when'文にスローされているようです。だから私は、 'valid'Response'メソッド自体を実行しようとしている' when'ステートメントに問題があると思います。 – DanHam

+0

これは非常に基本的な単体テストの基本的な質問ですが、 'validateResponse'メソッドを模擬して、' getAppointment'メソッドだけをテストしたいのではないでしょうか?または、同じクラスにある限り、複数のメソッドを同じ単体テストに含めることは有効ですか? – DanHam

0

this postに基づいて、私はvalidateResponseコールを模擬することができるようにするために行くAppointmentServiceの方法だと思います。だからここに私のテストは今、どのように見えるかです:

public class AppointmentServiceTest { 

    private UriInfo mockUriInfo; 
    private HttpResponse mockHttpResponse; 

    @Mock 
    private DataConnector mockDataConnector; 

    @Spy 
    private AppointmentsService appointmentsServiceSpy; 

    @InjectMocks 
    private AppointmentService appointmentService; 

    @Before 
    public void setUp() throws Exception { 
     MockitoAnnotations.initMocks(this); 
     appointmentsServiceSpy = spy(appointmentsService); 
     mockUriInfo(); 
     mockHttpResponse(); 
    } 

    private void mockUriInfo() { 
     mockUriInfo = mock(UriInfo.class); 
     when(mockUriInfo.getRequestUri()).thenReturn(
      URI.create("http://localhost:8080")); 
    } 

    private void mockHttpResponse() { 
     mockHttpResponse = mock(HttpResponse.class); 
     when(mockHttpResponse.getInputStream()).thenReturn(
      IOUtils.toInputStream("{\"appointment\":{}}")); 
    } 

    @Test 
    public void testGetAppointment() throws Exception { 
     when(mockDataConnector.getAppointmentById(Mockito.anyString())). 
      thenReturn(mockHttpResponse); 
     doReturn(new Appointment()).when(appointmentsServiceSpy).validateResponse(Mockito.any(HttpResponse.class), Mockito.any(UriInfo.class)); 
     appointmentServiceSpy.getAppointment(mockUriInfo, "12345"); 
     verify(mockDataConnector).getAppointmentById(Mockito.anyString()); 
    } 
} 

私はまだ実際のappointmentServiceSpy.getAppointmentコールで例外を取得していますが、私はそれは私がスパイを使用していますどのように関連する別の問題だと思います。元の質問の目的のために、doReturn().when()ステートメントでスパイを使用すると、when().thenReturn()ステートメントを使用するときに誤って呼び出されるメソッドの問題が解決されます。

関連する問題