2015-12-21 14 views
7

私は春の雲のユーレカを使って、いくつかのサービス(AとBと言うことができます)間で通信するようにしています。今では、単一のサービス(A)の私のサービス層をunittestするのが好きです。問題は、このサービス(A)が他のサービス(B)の情報を要求するためにクライアントを使用していることです。ユニットテストのためにユーレカ・フェーン・クライアントを模擬しました

特別な設定をせずにunittestを実行すると、次の例外が発生します。java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-b =>しかし、私はサーバーを実行したくありません。

私の質問は:フェイングクライアントを模擬する方法があるので、私はユリーカインスタンスとサービス(B)を実行しないで私のサービス(A)をユニットテストできるのですか?

編集: 私はfeignクライアント用のスタブを作成しました。スタブは、テストでスタブをインスタンス化するスプリングを強制的に起動するための主要コンポーネントとしてマークされています。
これは私が思いついた解決策です。

//the feign client 
@FeignClient("user") 
public interface UserClient { 
    UserEntity getUser(); 
} 

//the implementation i use for the tests 
@Component 
@Primary //mark as primary implementation 
public class UserClientTestImpl implements UserClient { 
    @Override public UserEntity getUser() { 
     return someKindOfUser; 
    } 
} 

答えて

4

質問がありますか...疑問に思われるのですか?私はしばしば、人々が "模擬テスト"の一部ではないはずのものに対する最初の解決策として "モック"を挙げていることをよく見ています。モッキングはテクニックであり、あらゆるものに対する解決策ではありません。 (here参照)。

まだコードの初期段階にいる場合は、Feign Clientの具体的なインスタンスに依存するのではなく、リファクタリングして別のものを使用してください。インタフェース、抽象クラス、特性などを使用できます。オブジェクト自体に依存しないでください。さもなければ、あなたはそれを "嘲笑"なければなりません。質問へ

public interface IWebClient { 
    public String get(...); 
    public String post(...); 
} 

:しかし、私は正確に同じことをするでしょう他のコードを持つことになります(それが装うの具体的なインスタンスになることを除いて)、私はその後何をしますか? まあ、機能テストを書いて、ローカルでセットアップできるWebサーバーのインスタンスを呼び出すことができます。あるいは、答えの1つでMarcin Grzejszczakが述べたように、Wiremockを使用することができます。

public class FeignClientWrapper implements IWebClient { 
    private feign = something 

    public String get() { 
    feign.get(...) 
    } 

    public String post() { 
    feign.post(...) 
    } 
} 

/他の場合はユニットテストは、アルゴリズムをテストするために使用され、ループ:どのように単位仕事を。モックを適合させるためのコードを書いてはいけません。逆の方法でなければなりません:コードの依存性が低くなるようにしてください。そうでなければ、スタブや擬似オブジェクトを使うことができます。あなたはその行動を検証する必要がありますか?あなたのコードで特定のメソッドが呼び出されることをテストする必要がありますか?または、特定のメソッドがX、Y、Zで3回連続して呼び出されるとしますか?さて、はい、嘲笑は大丈夫です。

それ以外の場合は、偽のオブジェクトを使用します。必要なのは、呼び出し/応答と多分ステータスコードだけをテストすることです。おそらく、あなたのコードが異なる出力(例えば、 "エラー"フィールドがJSONレスポンスにあるかどうか)、さまざまなステータスコード(クライアントのドキュメントが正しいと仮定して、GET、201 POST時など)。

+0

これは私がこれまでに思い付いたソリューションです: 装うインタフェース '@FeignClient( "ユーザー") パブリック・インタフェースUserClient {// 一部装う注釈 UserEntityのgetUser(); } '私がテストに使用 実装' @Component @PrimaryパブリッククラスUserClientTestImplがUserClient { @Override公共UserEntityのgetUser(){ 戻りsomeKindOfUserを実装します。 }} ' 基本的にそのあなたが@Markonを言及している方法。 –

+0

あなたは多分あなたの質問にコードを投稿してもらえますか?これはコメントでコードを読むのは難しい:D私はそれが助け幸せです。あなたが行動をテストしたい場合は、あなたはモックを使用することができます。あなたが「接続」をテストする場合は、セットアップ小さなウェブサーバ! :P – Markon

1

モックを使用する必要がある場合は、Wiremockを使用して特定のリクエスト(http://wiremock.org/stubbing.html)の応答をスタブすることができます。そうすれば、送信された実際のHTTPリクエストで統合テストを行います。ユニットテストのために、@Markonからの答えはとても良いです。

1

フェージングクライアントをモックすることは、マイクロサービスコンポーネントのテストで本当に役に立ちます。他のすべてのマイクロサービスを開始する必要はなく、1つのマイクロサービスをテストしたいとします。 Springを使用している場合(そしてあなたのように見えます)、@ MockBeanアノテーションと少しのMockitoコードが一緒になります。

@RunWith(SpringRunner.class) 
@SpringBootTest(webEnvironment = 
SpringBootTest.WebEnvironment.DEFINED_PORT) 
public class TestYourComponent { 
    @Configuration 
    @Import({YourConfiguration.class}) 
    public static class TestConfiguration { 
    } 

    @MockBean 
    private UserClient userClient; 

    @Test 
    public void someTest() 
    { 
     //... 
     mockSomeBehavior(); 
     //... 
    } 

    private void mockSomeBehavior() { 
     Mockito.doReturn(someKindOfUser).when(userClient).getUser(); 
    } 
} 
関連する問題