2016-05-26 5 views
1

WireMockを使用してリソースをモックアウトするユニットテストを作成しています。私は例外をスローするように私のエンドポイントをからかってる、例えば:"リクエストスコープはすでにシャットダウンされています"ユニットテストのジャージエラー

stubFor(
      post(urlEqualTo("/myEndpoint")) 
      .willReturn(aResponse().withStatus(errorCode) 
        .withHeader("Content-Type", "application/json") 
        .withBody(errorJson))); 

ここでテスト中である私のクライアントクラスの関連する部分がある:私がしようとしている私のユニットテストで

import javax.ws.rs.client.Client; 
import javax.ws.rs.client.WebTarget; 

public MyClient() { 

    private Client client; 
    private String baseUrl; 

    ... 

    public MyDto createObject(MyDto myDto) throws ClientErrorException { 
     String resourcePath = MessageFormat.format("myEndpoint"); 

     return client.target(baseUrl) 
       .path(resourcePath) 
       .request(MediaType.APPLICATION_JSON_TYPE) 
       .header(CONTENT_TYPE_HEADER, MediaType.APPLICATION_JSON) 
       .post(Entity.entity(myDto, MediaType.APPLICATION_JSON), MyDto.class); 
    } 
} 

例えば、キャッチし、返されるエラーに主張するのJUnitのExpectedExceptionを使用します。

NotAuthorizedExceptionStatusMatcherは私自身のカスタマイズされたマッチャークラスです
@Rule 
public ExpectedException thrown = ExpectedException.none(); 

@Test 
public void test_returnsError() { 
    ... 

    thrown.expect(NotAuthorizedException.class); 
    thrown.expect(NotAuthorizedExceptionStatusMatcher.hasStatusAndError(401, UNAUTHORISED_ERROR)); 

    myClient.createObject(new MyDto()); 
} 

import javax.ws.rs.NotAuthorizedException; 
import org.hamcrest.Description; 
import org.hamcrest.TypeSafeMatcher; 

public class NotAuthorizedExceptionStatusMatcher extends TypeSafeMatcher<NotAuthorizedException> { 

    public static NotAuthorizedExceptionStatusMatcher hasStatusAndError(int status, ErrorDescription entity) { 
     return new NotAuthorizedExceptionStatusMatcher(status, entity); 
    } 

    private final int expectedStatus; 
    private final ErrorDescription expectedError; 

    private int actualStatus; 
    private ErrorDescription actualError; 

    private NotAuthorizedExceptionStatusMatcher(int expectedStatus, ErrorDescription expectedError) { 
     this.expectedStatus = expectedStatus; 
     this.expectedError = expectedError; 
    } 

    @Override 
    public boolean matchesSafely(NotAuthorizedException exception) { 
     actualStatus = exception.getResponse().getStatus(); 
     actualError = exception.getResponse().readEntity(ErrorDescription.class); 
     return expectedStatus == actualStatus && expectedError.equals(actualError); 
    } 

    @Override 
    public void describeTo(Description description) { 
     description.appendValue(actualStatus) 
       .appendText(" was found instead of ") 
       .appendValue(expectedStatus) 
       .appendText(" and ") 
       .appendValue(actualError) 
       .appendText(" was found instead of ") 
       .appendValue(expectedError); 
    } 

} 

私のマッチャがexception.getResponse()readEntity(ErrorDescription.class)を行おうとすると、私はエラーを取得:。

java.lang.IllegalStateException: Request scope has been already shut down. 
     at jersey.repackaged.com.google.common.base.Preconditions.checkState(Preconditions.java:149) 
     at org.glassfish.jersey.process.internal.RequestScope.retrieveCurrent(RequestScope.java:239) 
     at org.glassfish.jersey.process.internal.RequestScope.runInScope(RequestScope.java:416) 
     at org.glassfish.jersey.client.InboundJaxrsResponse.readEntity(InboundJaxrsResponse.java:108) 
     at MyProject.NotAuthorizedExceptionStatusMatcher.matchesSafely(NotAuthorizedExceptionStatusMatcher.java:28) 
     at MyProject.NotAuthorizedExceptionStatusMatcher.matchesSafely(NotAuthorizedExceptionStatusMatcher.java:8) 
     at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65) 
     at org.hamcrest.core.AllOf.matches(AllOf.java:27) 
     at org.hamcrest.DiagnosingMatcher.matches(DiagnosingMatcher.java:12) 
     at org.junit.internal.matchers.StacktracePrintingMatcher.matchesSafely(StacktracePrintingMatcher.java:29) 
     at org.junit.internal.matchers.StacktracePrintingMatcher.matchesSafely(StacktracePrintingMatcher.java:14) 
     at org.hamcrest.TypeSafeMatcher.matches(TypeSafeMatcher.java:65) 
     at org.hamcrest.MatcherAssert.assertThat(MatcherAssert.java:12) 
     at org.junit.Assert.assertThat(Assert.java:956) 
     at org.junit.Assert.assertThat(Assert.java:923) 
     at org.junit.rules.ExpectedException.handleException(ExpectedException.java:252) 
     at org.junit.rules.ExpectedException.access$000(ExpectedException.java:106) 
     at org.junit.rules.ExpectedException$ExpectedExceptionStatement.evaluate(ExpectedException.java:241) 
     at com.github.tomakehurst.wiremock.junit.WireMockRule$1.evaluate(WireMockRule.java:67) 
     at org.junit.rules.RunRules.evaluate(RunRules.java:20) 
     at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78) 
     at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57) 
     at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290) 
     at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71) 
     at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288) 
     at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58) 
     at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268) 
     at org.junit.runners.ParentRunner.run(ParentRunner.java:363) 
     at org.apache.maven.surefire.junit4.JUnit4Provider.execute(JUnit4Provider.java:242) 
     at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:137) 
     at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:112) 
     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:497) 
     at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:189) 
     at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:165) 
     at org.apache.maven.surefire.booter.ProviderFactory.invokeProvider(ProviderFactory.java:85) 
     at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:115) 
     at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:75) 

この同じコードは、私はのtry-catchを使用している場合に動作するようですブロックを例外にアサートするが、私はExpectedExceptionアプローチを好む。何が原因だろうか?私はそれが私が使用しているフレームワークの組み合わせだと思うが、私はここからどこに行くのかは分かりません。

+1

レスポンスボディは一度しか読むことができます。問題はどこかにあると思う。あなたのマッチャーであなたは 'readEntity'を試みています。コードを見てみましたが、それは見栄えが良い場所だと思います。 –

+0

私はそれについて読んだが、私はチェックした。私が使用している依存関係の中のどこか他の場所でも読まれていない限り。また、try-catchブロックアプローチでthrown.expectを置き換えると、なぜそれがうまくいくように見えるとは思わないでしょう。私の直感は、それが問題を引き起こしているスローされたアプローチアプローチに暗黙の何かです。 –

+1

クライアントでは、暗黙の読み取りが行われます。 dtoではなく、クライアントで 'Response'を取得してから、' [Response.bufferEntity'](http://docs.oracle.com/javaee/7/api/javax/ws/rs)を呼び出すことができます。 /core/Response.html#bufferEntity--)、あなたは 'response.readEntity(Dto)'を返すことができます。それはトリックを行うべきだと思います –

答えて

0

これは、テストクラスのルールの順序によって発生する可能性があります。奇妙に聞こえるかもしれませんが、ルールの順序が[WireMock、ExpectedException]と解釈された場合、 junitフレームワークは実際にはその順序でビルドします。このルールはテストの周りのデコレータとして設計されているので、各ルールは@Beforeブロックの前と@Afterの後にアクションを取ることができます。上記の例ではそう

、ルールは[WireMock、ExpectedException]解決される場合、実行順序は次のようになります。

  1. あれば(サーバ

  2. ExpectedExceptionのINITを開始WireMock )

  3. @Before実行

  4. テスト

  5. @After実行実行

  6. ExpectedException評価とアクション

  7. WireMockがサーバー

をシャットダウンし、私はこのような場合は、実際にあなたが探しているものだと思います。

我々は、しかしWireMockとExpectedExceptionの順に切り替える場合:

  1. ExpectedExceptionの初期化(もしあれば)

  2. @Before実行

  3. 実行サーバー起動WireMockを試験

  4. @After実行WireMockは、サーバー

    をシャットダウン
  5. ExpectedException評価とアクションExpectedExceptionルールは例外で応答を評価するために許可されている時間によって、その後

すべてのサービスと状態Wiremockによって破壊されました。 RuleChainを使用して


は、ルールの順序を保証する、と(私はそれをエミュレートすることができた程度の)問題を修正します。

Swap out the passOrder and failOrder chains to see the test fail!

public class WiremockTest { 

    public WireMockRule wireMockRule = new WireMockRule(8089); 
    public ExpectedException thrown = ExpectedException.none();  
    @Rule 
    public RuleChain passOrder = RuleChain.outerRule(wireMockRule).around(thrown); 
    //public RuleChain failOrder = RuleChain.outerRule(thrown).around(wireMockRule); 

    @Test 
    public void exampleTestExpectConnectionException() throws Exception { 
     thrown.expect(ConnectionObjectContainer.class); 

     //Custom matcher that gets something from the cached connection after the failure occurs. 
     thrown.expect(new BaseMatcher<ConnectionObjectContainer>(){ 

      public boolean matches(Object item) { 
       ConnectionObjectContainer container = (ConnectionObjectContainer) item; 
       try { 
        //XXX This line is intended to mimic the NotAuthorizedException class behavior 
        System.out.println(container.getResponseCode()); 

       } catch (IOException exception) { 
        throw new RuntimeException(exception); 
       } 
       return true; 
      } 

      public void describeTo(Description description) { 
       //Not used in sample 
      }}); 


     stubFor(get(urlPathMatching("/my/resource/[0-9]+")).willReturn(aResponse().withStatus(200).withHeader(
      "Content-Type", "text/xml").withBody("<response>Some content</response>"))); 

     URL obj = new URL("http://localhost:8089/my/resource/121"); 
     HttpURLConnection con = (HttpURLConnection) obj.openConnection(); 

     // optional default is GET 
     con.setRequestMethod("GET"); 

     throw new ConnectionObjectContainer(con); 
    } 



    /** 
    * My Exception class that caches the HttpURLConnection and provides an accessor for the response code to the Matcher of my 
    * ExpectedException configuration. 
    * 
    * @since Jun 17, 2016 
    * 
    */ 
    public class ConnectionObjectContainer extends Exception { 
     HttpURLConnection connection; 
     public ConnectionObjectContainer(HttpURLConnection conn) { 
      this.connection = conn; 
     } 

     public int getResponseCode() throws IOException { 
      return connection.getResponseCode(); 
     } 
    } 


} 
関連する問題