-1

サンプルのシングルトンは次のとおりです。

public class Singleton
{
    private static Singleton _instance = new Singleton();

    private Singleton()
    {
        //do stuff
    }

    public static Singleton Get()
    {
        return _instance;
    }
}

このシングルトン クラスで複数のテストを実行しようとしていますが、最初のテストは常に正常に機能します。new Singleton()基本的に、コンストラクターを作成すると呼び出されることがわかります。または、Singleton.Get()コンストラクターを呼び出すと呼び出されます。 テストは個別に正常に動作しますが、静的フィールドが設定されており、手動で null に設定しても、次のテストではリセットされません。ここでは自動テストが重要であるため、これは私にとって問題です。では、どうすればそれをリセットできますか?

これまでに AppDomain を調査したところ、各テストを独自のアセンブリに配置して手動で実行できることがわかりました。もちろん、VSはアセンブリごとに一意の AppDomain を既に使用しているため、自動的に実行できますが、これは多くのテスト アセンブリであり、少しばかげているようです。私はそれに代わるものを探しています。

注:コードの品質に関するアドバイスは必要ありません。 これは私がテストしているコードであり、私が書いたものではありません。最初にテストするまで、コードを変更しません。 私はこれを徹底的に調査しましたが、「シングルトンを使用しないでください」と回答されていない質問は見つかりませんでした。コードのアドバイスには興味がありません。これは CodeReview ではなく、StackOverflow です。

要求される追加情報

現在、Visual Studio のビルトイン テスト フレームワークを使用してテストを実行しています。MSBuild に移行しても、これが引き続き機能することを望みます。テストのために外部アプリケーションを手動でトリガーすることを除外するわけではありませんが、実行が難しくなります。

4

5 に答える 5

2

AppDomains を誤解しています。

テストごとに新しい AppDomain を作成し、すべてのテスト アセンブリをそこにロードして、各ドメインで 1 つのテスト メソッドのみを呼び出すだけです。
ただし、おそらくかなり遅いでしょう。

于 2013-04-17T19:49:59.847 に答える
1

@redtuna @drch および @SLaks からの多数のアドバイスと、多くのグーグル検索の後、これを行う方法を決定しました。

ステップ 1:テスト クラスはから継承する必要がありますMarshalByRefObject

public class UnitTest1 : MarshalByRefObject

ステップ 2:この次の部分は、各テストを独自の で実行するためのカスタム メソッドAppDomainです。

private void RunTestInCustomDomain(string methodName)
{
    // selecting the dll from the debug directory using relative directories
    var testDll = @"..\..\..\UnitTests\bin\Debug\UnitTests.dll";
    // first verify the dll exists
    Assert.IsTrue(File.Exists(testDll));
    var assemblyName = AssemblyName.GetAssemblyName(testDll).FullName;
    var domain = AppDomain.CreateDomain(methodName, null, new AppDomainSetup()
    {
        // This is important, you need the debug directory as your application base
        ApplicationBase = Path.GetDirectoryName(testDll)
    });
    // create an instance of your test class
    var tests = domain.CreateInstanceAndUnwrap(assemblyName, typeof(UnitTest1).FullName) as UnitTest1;
    var type = tests.GetType();
    var method = type.GetMethod(methodName);
    // invoke the method inside custom AppDomain
    method.Invoke(tests, new object[]{});
    // Unload the Domain
    AppDomain.Unload(domain);
}

ステップ 3:次のトリックは、テスト メソッドがこのカスタム メソッドを呼び出すことです。そのため、テストは属性なしでパブリックメソッドに書き込まれます。[TestMethod]

[TestMethod]
[DeploymentItem("UnitTests.dll")]
public void TestMethod1()
{
    RunTestInCustomDomain("actual_TestMethod1");
}

public void actual_TestMethod1()
{
    // Assert Stuff
}

完全を期すために: テストごとに初期化またはクリーンアップを実行する必要がある場合は、TestMethod が actual_TestMethod とは異なる AppDomain で実行されているため、手動で呼び出す必要があります。

public void actual_TestMethod1()
{
    // Assert Stuff
    TestCleanup();
}

編集:これらのメソッドは別の AppDomain で実行されているため、コード カバレッジは機能しないことに注意してください :(。誰かがこの機能に加えてその機能を取得する方法を見つけた場合は、お知らせください。

于 2013-04-18T15:41:28.303 に答える
1

Singleton次のようにクラスを設計できます。

public class Singleton
{
    private static Singleton _instance;
    private static object _instanceLock = new object();

    private Singleton()
    {
        //do stuff
    }

    public static Singleton Get()
    {
        if (_instance == null)
        {
            lock(_instanceLock)
            {
                if (_instance == null)
                {
                    _instance = new Singleton();
                }
            }
        }

        return _instance;
    }

    public static void Clear()
    {
        if (_instance != null)
        {
            lock(_instanceLock)
            {
                if (_instance != null)
                {
                    _instance = null;
                }
            }
        }
    }
}

Singleton.Clear()次に、次のように、各テストを開始する前に呼び出す必要があります。

[TestInitialize]
public void Initialize()
{
    Singleton.Clear();
}
于 2013-04-17T19:49:59.493 に答える
0

ただのアイデア:

もちろん、それをnullに設定すると、変数が指しているものではなく、変数がnullに設定されます。しかし、それ自体を取得できたらどうでしょうかSingleton... s を使用してそれを行うことができるようExpressionです。MemberExpression からオブジェクトを取得するを参照してください。

于 2013-04-17T20:49:05.897 に答える