いくつかのサービス(AとBとしましょう)間の通信に、Spring Cloudのeurekaを使用しています。ここで、単一のサービス(A)のサービスレイヤーを単体テストしたいと思います。問題は、このサービス(A)が偽のクライアントを使用して他のサービス(B)の情報を要求していることです。
特別な設定なしでユニットテストを実行すると、次の例外がスローされます:Java.lang.RuntimeException: com.netflix.client.ClientException: Load balancer does not have available server for client: service-b
=>しかし、どのサーバーも実行したくありません。
私の質問は:偽のクライアントを模擬する方法はありますか?それで、eurekaインスタンスとサービス(B)を実行せずにサービス(A)を単体テストできますか?
編集:私は結局、偽のクライアントのためのスタブを作成することになりました。スタブは、テスト内でスタブをインスタンス化するスプリングを強制する主要コンポーネントとしてマークされています。
これが私が思いついたソリューションです。
//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;
}
}
問題は...あなたはあざける必要さえありますか? 「単体テストの一部であってはならない」ものに対する最初の解決策として、「モック」に言及する人がよくいます。モッキングはテクニックであり、すべてに対する解決策ではありません。 ( ここ を参照)。
コードの初期段階にある場合は、Feign Clientの具体的なインスタンスに依存するのではなく、リファクタリングして、何か他のものを使用してください。インターフェース、抽象クラス、特性など、必要なものを使用できます。オブジェクト自体に依存しないでください。依存しない場合は、「モック」する必要があります。
public interface IWebClient {
public String get(...);
public String post(...);
}
質問に対して:しかし、まったく同じように動作する他のコードがあります(Feignの具体的なインスタンス上にあることを除いて)、次に何をしますか?まあ、機能テストを作成して、ローカルでセットアップできるWebサーバーのインスタンスを呼び出すことができます。または、答えの1つでMarcin Grzejszczakが述べたように、Wiremockを使用することもできます。
public class FeignClientWrapper implements IWebClient {
private feign = something
public String get() {
feign.get( ... )
}
public String post() {
feign.post( ... )
}
}
ユニットテストは、ループ、if/else、ループをテストするために使用されます:unitsの動作方法。モックをフィットさせるコードを記述しないでください-それは逆でなければなりません。コードの依存関係を少なくし、動作を確認する必要がある場合にのみモックする必要があります(それ以外の場合は、スタブまたは偽のオブジェクトを使用できます)。動作を確認する必要がありますか?特定のメソッドがコードで呼び出されることをテストする必要がありますか?または、特定のメソッドがX、Y、Zで3回続けて呼び出されるということですか?さて、はい、あざけることは大丈夫です。
それ以外の場合は、偽のオブジェクトを使用します。必要なのは、呼び出し/応答と、おそらくステータスコードだけをテストすることです。おそらく必要なのは、コードがさまざまな出力(たとえば、「エラー」フィールドがJSON応答に存在するかどうか)にどのように反応するかをテストすることだけです。 POST時など)。
モックを使用する必要がある場合は、Wiremockを使用して、特定の要求に対する応答をスタブ化できます http://wiremock.org/stubbing.html 。このようにして、送信された実際のHTTPリクエストを使用して統合テストを行います。ユニットテストの場合、@ Markonからの回答は非常に優れています。
偽のクライアントのモックは、マイクロサービスコンポーネントのテストで非常に役立ちます。他のすべてのマイクロサービスを開始する必要なく、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();
}
}