2017-04-10 2 views
0

私はこのようになり、データベースの方法があるとします。トランザクションを使用しないSQLメソッドのテスト?

public void insertRow(SqlConnection c) 
{ 
    using (var cmd = new SqlCommand("insert into myTable values(@dt)",c)) 
    { 
     cmd.Parameters.Add(new SqlParameter("@dt",DbType.DateTime)).Value = DateTime.Now; 
     cmd.ExecuteNonQuery(); 
    } 
} 

は、今私は、このメソッドをテストするとします。私は挿入の結果をテストした後の変更をロールバックできるように、だから、私は、トランザクション内でこのメソッドをラップしようとしたテストケースを書く:

public void testInsertRow() 
{ 
    SqlConnection c = new SqlConnection("connection.string.here"); 
    SqlTransaction trans = c.BeginTransaction(); 
    insertRow(); 
    // do something here to evaluate what happened, e.g. query the DB 
    trans.Rollback(); 
} 

しかしこれは動作しない、ので:

ExecuteNonQueryでは、コマンドに割り当てられた接続が保留中のローカルトランザクション内にある場合、コマンドにトランザクションが必要です。コマンドのTransactionプロパティが初期化されていません。

トランザクションを受け入れるために、すべて単一のデータベースメソッドを書き換え、その後、トランザクションのための方法にnullを渡すためにすべての単一の呼び出しを書き換えることなく、これを達成する方法はありますか?

例えば、これは動作します:

public void insertRow(SqlConnection c, SqlTransaction t) 
{ 
    using (var cmd = new SqlCommand("insert into myTable values(@dt)",c)) 
    { 
     if (t != null) cmd.Transaction = t; 
     cmd.Parameters.Add(new SqlParameter("@dt",DbType.DateTime)).Value = DateTime.Now; 
     cmd.ExecuteNonQuery(); 
    } 
    c.Close(); 
} 

しかし、その後、私はそれぞれ、すべてのデータベースメソッドの呼び出しそのnullパラメータを含めることを書き換え、またはそれぞれ、すべてのデータベースメソッドのオーバーライドの署名を書くことのどちらか持っています自動的にnullに入ります。

public void insertRow(SqlConnection c) { insertRow(c, null); } 

データベース呼び出しのトランザクションベースのテストを許可するにはどうすればよいですか?

+2

[のTransactionScope](https://msdn.microsoft.com/en-us/library/ee818746(V = vs.110).aspxの) –

+0

は、あなたがロールバックする前に、あなたの接続を閉じているように私には思えます。 – Lunyx

+0

@ Lunyxあなたは正しいです、そこにいるはずはありませんでした。もちろんそれを削除しても問題は解決しませんが、指摘してくれてありがとうございます。 – fdmillion

答えて

2

あなたは今、これはあなたが実行している複数の並列テストを持っている場合、テストがお互いをブロックするようになりますトランザクション

public void testInsertRow() 
{ 
    using(TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew)) 
    { 
     SqlConnection c = new SqlConnection("connection.string.here"); 
     insertRow(c); 
     // do something here to evaluate what happened, e.g. query the DB 

     //do not call scope.Complete() so we get a rollback. 
    } 
} 

に自動的に接続を追加するTransactionScopeを使用することができます。データベースがそれをサポートするように設定されている場合、スナップショットの分離を行うことができるので、並行テストからの更新は相互にロックされません。

public void testInsertRow() 
{ 
    using(TransactionScope scope = new TransactionScope(TransactionScopeOption.RequiresNew, 
                 new TransactionOptions(IsolationLevel = IsolationLevel.Snapshot)) 
    { 
     SqlConnection c = new SqlConnection("connection.string.here"); 
     insertRow(c); 
     // do something here to evaluate what happened, e.g. query the DB 

     //do not call scope.Complete() so we get a rollback. 
    } 
} 
+0

完璧に動作するようです。私が気づくのは、範囲外の接続を宣言すると、スコープが動作しないように見えるということだけです。したがって、ロールバックしてより多くのアクションを実行したい場合は、新しい接続を開く必要があるように見えます。大したことではなく、気づいただけです。 – fdmillion

関連する問題