8

私はこれを再び取り上げることを嫌いますが、私は自分のテストで何かを保護する方法を本当に理解しようとしています。

実際に何らかのアクションを実行する別のメソッドを呼び出す前に、プライベートメソッドを呼び出すパブリックメソッド(以下)があります。壊滅的な可能性があるため、プライベートメソッドの呼び出しが削除されないようにしたいと思います。私はここここ、そしてここでいくつかの調査を行いました、そしてそれらはすべて私的な方法をテストしないと言います。私はそれを理解できると思いますが、このコード行の削除を防ぐにはどうすればよいですか?

ご覧のとおり、パブリックメソッドはvoidを返すため、パブリックメソッド呼び出しの結果をテストすることはできません。そして、直接テストする単体テストがありApplicationShouldBeInstalled()ます。

public void InstallApplications()
{
    foreach (App app in this._apps)
    {
        // This is the line of code that can't be removed. How can I make
        // sure it doesn't get removed?
        if (!ApplicationShouldBeInstalled(app)) { continue; }

        // This simply can't run unless it passes the above call.
        CommonUtility.Container.Resolve<IAppInstaller>().InstallApplication(this, app);
    }                       
}

編集-私はJerKimballの答えに基づいてこれを使いました。

基本的に、私は(Moqからの)Mockオブジェクトを使用し、そのメソッドが予想される回数呼び出されたことを確認します。

[TestMethod()]
public void ApplicationShouldBeInstalledTest_UseCase13()
{
    var mockAppInstaller = new Mock<IAppInstaller>();
    mockAppInstaller.Setup(m => m.InstallApplication(It.IsAny<ApplicationServer>(),
        It.IsAny<Application>()));
    CommonUtility.Container.RegisterInstance<IAppInstaller>(mockAppInstaller.Object);

    // Actual test code here

    appServer.InstallApplications();
    mockAppInstaller.Verify(x => x.InstallApplication(It.IsAny<ApplicationServer>(),
        It.IsAny<Application>()), Times.Never());
}

これを手放すことはできません。その編集はただ醜いです。実際のモッククラスを作成する必要がありますが、このアプローチははるかにクリーンです。

モック実装:

public class MockAppInstaller : IAppInstaller
{
    public bool Invoked { get; set; }

    public void InstallApplication(ApplicationServer server, Application app)
    {
        this.Invoked = true;
    }
}

試験方法:

[TestMethod()]
public void ApplicationShouldBeInstalledTest_UseCase14()
{
    MockAppInstaller mockAppInstaller = new MockAppInstaller();
    CommonUtility.Container.RegisterInstance<IAppInstaller>(mockAppInstaller);

    // Actual test code here

    appServer.InstallApplications();
    Assert.AreEqual(true, mockAppInstaller.Invoked);
}
4

4 に答える 4

5

壊滅的な事態になる可能性があるため、プライベート メソッドの呼び出しが削除されないようにしたいと考えています。

それは簡単なはずです。大惨事は非常に簡単に見つけることができます。したがって、パブリック メソッドを呼び出すテストを実行し、壊滅的な事態が発生したかどうかを確認してください。大惨事から保護されたプライベート メソッド内のコードは、事実上、パブリック メソッドを実行することの目に見える副作用です...一方、それがプライベート メソッド呼び出しによるものであったという事実は実装の詳細です。

したがって、この場合、基本的に(何らかの理由で) インストールしてはならないInstallApplicationsアプリケーションを作成し、呼び出すときにインストールされていないことを検証する必要があります。

于 2013-02-14T21:43:49.380 に答える
3

考えられるオプションの 1 つを次に示します...確かに、これは非常に単純化されていますが、少し変更することで状況に適用できる可能性があります。

Appそれが次のように見えるとしましょう:

public class App 
{
    public virtual bool CanBeInstalled {get; set;}
}

ApplicationShouldBeInstalledのようになります。

private bool ApplicationShouldBeInstalled(App app) { return app.CanBeInstalled; }

次のように、「期待されるアクションを介して確認する」単体テストを作成できます。

void Main()
{
    var sut = new ThingToTest();    

    var mockApp = new Mock<App>();
    var wasCanBeInstalledChecked = false;
    mockApp
       .SetupGet(app => app.CanBeInstalled)
       .Callback(() => wasCanBeInstalledChecked = true);

    // of course, whatever you'd do here to get an app into this class
    sut.AddApp(mockApp.Object);

    sut.InstallApplications();
    Debug.Assert(wasCanBeInstalledChecked == true);
}
于 2013-02-14T21:51:28.890 に答える
1

このメソッドを公開しても、呼び出されたかどうかはわかりません。公開することで、テストすることができますが、それ以上のことはできません。

ifステートメントを通常の方法で使用すると、コードがより明確になります。その目的は、現在この行を削除しているプログラマーにとっても明らかです。

public void InstallApplications()
{
    foreach (App app in this._apps)
    {
        if (ApplicationShouldBeInstalled(app)) {
            CommonUtility.Container
                .Resolve<IAppInstaller>()
                .InstallApplication(this, app);
        }
    }                       
}

このメソッドが呼び出されたときにカウンターを増やすこともできます。その後、単体テストでこのカウンターをテストできます。

注: このカウンターinternalを作成し、InternalsVisibleToAttribute.

アップデート

このカウンターを実装する方法は次のとおりです。

public int ApplicationShouldBeInstalled_Count { get; private set; }

public bool ApplicationShouldBeInstalled(App app)
{
    ApplicationShouldBeInstalled_Count++;
    ...
}

次にテスト

var sut = new MyInstallerClass();
int oldCount = sut.ApplicationShouldBeInstalled_Count;
sut.InstallApplications();
int newCount = sut.ApplicationShouldBeInstalled_Count;

Assert.AreEqual(oldCount + sut.Apps.Count, newCount);
于 2013-02-14T21:51:20.327 に答える
1
public void InstallApplications()
{
    foreach (App app in this._apps.ThatShouldBeInstalled)
    {
        CommonUtility.Container.Resolve<IAppInstaller>().InstallApplication(this, app);
    }                       
}

ミックスに横方向の思考を少し入れようと思っただけです...

うっかり抜いてしまわないように、うっかり抜いてしまいましょう。:)

于 2013-02-14T22:05:13.870 に答える