web-dev-qa-db-ja.com

DROP DATABASEステートメントはユーザートランザクション内では使用できません

この質問がここにあるかどうかは本当にわかりませんが、誰かが私を助けてくれることを願っています。

データベースに至るまでの統合テストを作成しました(mssql localDBを使用)。各テストを独自のデータで個別に実行したい-各テストを実行する前に、偽のデータでデータベースを再シードしたい。私は成功せずにトランザクションでそれを実装しようとしました。ここに私がそれを引き出そうとした方法があります:

public class TestDbInitializer : DropCreateAlways<MyContext>()
{
    public static List<Item> Items;

    public override Seed(DbContext context)
    {
        Items = new List<Item>();

        // Adding items
        // .. 

        Items.ForEach(x => context.Add(x));

        context.SaveChanges();
    }
}


public class BaseTransactionsTests
{
    private TransactionScope _scope

    [TestInitialize]
    public void Initialize()
    {
        _scope = new TransactionScope();
    }

    [TestCleanup]
    public void Cleanup()
    {
        _scope.Dispose();
    }
}

[TestClass]
public class IntegrationTests : BaseTransactionsTests

private IDependenciesContainer _container;

public static void AssemblyInit(TestContext context)
{
    Database.SetInitializer(new TestDbInitializer());

    _container = new DependenciesContainer();

    // Registers all my application's dependencies
    _container.RegisterAll();
}

[TestInitialize]
public void Initialize()
{
    using (var context = new MyContext("TestsDatabase"))
    {
        context.Initialize(true);
    }
}

[TestMethod]
public void TestAddItem()
{
    var controller = _container.Resolve<MyController>();

    var result = controller.AddItem(new Item({Name = "Test"}))

    var goodResult = result as OkNegotiatedResult<string>();

    if (result == null)
        Assert.Fail("Bad result")

    using (var context = new MyContext("TestsDatabase"))
    {
        Assert.AreEqual(context.Items.Count, TestDbInitializer.Items.Count + 1)
    }
}

テストで依存関係インジェクターを使用して、すべての依存関係を一度登録します(AssemblyInitialize)。

テスト用のDBインスタンスと、偽のデータSeedメソッドを使用した特定のDropCreateAlwaysイニシャライザを作成しました。これは、AssemblyInitializeでイニシャライザとして設定しました。

各テストを実行する前に、偽のデータでデータベースを再シードします。その場合、トランザクションスコープを保持する基本クラスを実装しました。

テストを実行すると、TestInitializeにデータベースをシードすると、次の例外がスローされます。

DROP DATABASE statement cannot be used inside a user transaction

どのように対処すればよいですか?さらに、これらの統合テストの私の実装についてどう思いますか?何を改善できるでしょうか?

4
S. Peter

データベースが存在する場合はそれを削除する別の初期化子を作成し、トランザクション処理コードの外部にデータベースを作成します。これが何らかの理由で失敗した場合、(おそらく)テストを失敗させて、失敗した理由を調査できます。

から [〜#〜] msdn [〜#〜]

CREATE DATABASEステートメントは、自動コミットモード(デフォルトのトランザクション管理モード)で実行する必要があり、明示的または暗黙的なトランザクションでは使用できません。

必要に応じて、個別のテストごとにこれを行うことができます。

  1. DROP DATABASE存在する場合
  2. CREATE DATABASE
  3. 必要なDDLを作成する
  4. DML単体テストを実行する
  5. DROP DATABASE

しかし、それはやり過ぎです。すべてのテストの最初にデータベースを作成し、最後にそれをドロップするだけです。各ユニットテストは、以降のテストの要件に応じて、ロールバックまたはコミットされるトランザクションにラップできます。

理由CREATE DATABASEをトランザクション内で使用できない理由を説明するリソースを探しましたが、見つかりませんでした。 Kenneth Fisher は、トランザクションで機能しないすべてのコマンドを示す次のTechNetリンクを提供しました。

トランザクションで許可されているTransact-SQLステートメント

私たちの推測では、トランザクションではないファイルシステムに影響を与えるため、それらの多くは許可されていません。

6
Max Vernon