1

私は最近、この興味深い概念に出くわしました。これにより、テストの労力を大幅に節約できる可能性があります。私が理解していないのは、プロバイダーを実行時にどのように注入できるかということです。

シナリオは簡単です。選択したモックフレームワークを使用して実行時にモックオブジェクトを構築していますが、モックであるため、生成されたクラスの名前が事前にわかりません(したがって、事前に構成することはできません)。 、したくない)。

ユニットテストでこの手法をうまく利用した人はいますか?

ありがとうございました。

4

2 に答える 2

3

その記事で説明されている概念は、バックグラウンドでサービスロケーターを使用するアンビエントコンテキストです。

静的プロパティとServiceLocatorを使用しているため、このパターンは単体テストには非常に不便です。このシングルトンを使用するコードを検証するテストを実行できるようにするには、有効なService Locatorをセットアップし、テストの使用に関心のあるシングルトン(おそらくモックインスタンス)で構成する必要があります。

「シングルトンは好きですか?」という理由で、記事に示されている例でさえ、すでにこれらの問題に悩まされています。コード、テストするのは難しい:

if (DialogDisplayer.getDefault().yesOrNo(
    "Do you like singletons?"
)) {
    System.err.println("OK, thank you!");
} else {
    System.err.println(
        "Visit http://singletons.apidesign.org to"
        + " change your mind!"
    );
}

より良い代替策は、コンストラクターインジェクションを使用してそのシングルトンをインジェクトすることです(私のフランス語を失礼しますが、私はネイティブJavaスピーカーではありません):

public class AskTheUserController
{
    private DialogDisplayer dialogDisplayer;
    private MessageDisplayer messageDisplayer;

    public AskTheUserController(DialogDisplayer dialogDisplayer,
        MessageDisplayer messageDisplayer)
    {
        this.dialogDisplayer = dialogDisplayer;
        this.messageDisplayer = messageDisplayer;
    }

    public void AskTheUser()
    {
        if (this.dialogDisplayer.yesOrNo(
            "Do you like singletons?"
        )) {
            this.messageDisplayer.display("OK, thank you!");
        } else {
            this.messageDisplayer.display(
                "Visit http://singletons.apidesign.org to"
                + " change your mind!"
            );
        }
    }
}

そのコードには別の「隠された」依存関係がありました:System.err.printlnMessageDisplayerインターフェイスを使用して抽象化されました。このコードには、いくつかの明らかな利点があります。

  • 両方の依存関係を注入することにより、コンシューマーはそれらの依存関係がシングルトンであることを知る必要さえありません。
  • コードは、必要な依存関係を明確に伝えます。
  • コードは、モックオブジェクトを使用して簡単にテストできます。
  • テストコードは、サービスロケーターを構成する必要はありません。

テストは次のようになります。

@Test
public void AskTheUser_WhenUserSaysYes_WeThankHim()
{
    // Arrange
    bool answer = true;

    MockMessageDisplayer message = new MockMessageDisplayer();
    MockDialogDisplayer dialog = new MockDialogDisplayer(answer);

    AskTheUserController controller =
        new AskTheUserController(dialog, message);

    // Act
    controller.AskTheUser();

    // Assert
    Assert.AreEqual("OK, thank you!", message.displayedMessage);
}

@Test
public void AskTheUser_WhenUserSaysNo_WeLetHimChangeHisMind()
{
    // Arrange
    bool answer = true;

    MockMessageDisplayer message = new MockMessageDisplayer();
    MockDialogDisplayer dialog = new MockDialogDisplayer(answer);

    AskTheUserController controller =
        new AskTheUserController(dialog, message);

    // Act
    controller.AskTheUser();

    // Assert
    Assert.IsTrue(
        message.displayedMessage.contains("change your mind"));
}

記事に示されているように、「注入可能なシングルトン」パターンを使用している場合、テストコードは上記のコードほど明らかになることはありません。

于 2012-08-13T13:39:19.227 に答える
1

シングルトンには何の問題もありません。シングルトンは、どのソフトウェアでも便利で必要な概念です。問題は、静的フィールドとメソッドを使用してそれらを実装するべきではないということです。

私はGuiceを使用してシングルトンを注入し、コードベースで静的を使用して非常に長い間テストする必要はありませんでした。

Guiceでテスト可能なシングルトンを実現する方法を説明するのに役立つと思われるリンクを次に示します。

于 2012-08-13T17:24:21.293 に答える