4

テスト駆動開発にもっと慣れようとしています。これまでのところ、いくつかの簡単な例を見てきましたが、たとえば DAL の次のメソッドのような複雑なロジックにアプローチするにはまだ問題があります。

public static void UpdateUser(User user)
        {
            SqlConnection conn = new SqlConnection(ConfigurationSettings.AppSettings["WebSolutionConnectionString"]);
            SqlCommand cmd = new SqlCommand("WS_UpdateUser", conn);

            cmd.CommandType = CommandType.StoredProcedure;
            cmd.Parameters.Add("@UserID", SqlDbType.Int, 4);
            cmd.Parameters.Add("@Alias", SqlDbType.NVarChar, 100);
            cmd.Parameters.Add("@Email", SqlDbType.NVarChar, 100);
            cmd.Parameters.Add("@Password", SqlDbType.NVarChar, 50);
            cmd.Parameters.Add("@Avatar", SqlDbType.NVarChar, 50);
            cmd.Parameters[0].Value = user.UserID;
            cmd.Parameters[1].Value = user.Alias;
            cmd.Parameters[2].Value = user.Email;
            cmd.Parameters[3].Value = user.Password;
            if (user.Avatar == string.Empty)
                cmd.Parameters[4].Value = System.DBNull.Value;
            else
                cmd.Parameters[4].Value = user.Avatar;

            conn.Open();
            cmd.ExecuteNonQuery();
            conn.Close();
        }

この方法の適切な TDD プラクティスは何ですか?

4

2 に答える 2

7

コードは既に書かれているので、代わりにテストが難しい理由について話しましょう。ここでの主な問題は、このメソッドが純粋に副作用であるということです: 何も返さない (void)、そしてその効果はコード内のオブジェクトランドでは観察できません - 観察可能な副作用はデータベースのどこか遠くにあるはずです、レコードが更新されました。

「これらの条件を考えると、これを行うとき、これを観察する必要があります」という観点から単体テストを考えると、前提条件(接続が与えられた場合有効な DB に) および事後条件 (レコードが更新された) は単体テストから直接アクセスできず、そのコードが実行されている場所に依存します (2 台のマシンで「そのまま」コードを実行する 2 人のユーザーには理由がありません)。同じ結果が期待できます)。

これが、技術的に、純粋にインメモリではないテストが単体テストと見なされず、「古典的な TDD」の領域から少し外れている理由です。

あなたの状況では、ここに2つの考えがあります:

1) 統​​合テスト。コードがデータベースでどのように機能するかを確認したい場合は、単体テストではなく統合テストの領域にいます。BDD のような TDD にインスパイアされた手法が役立ちます。"コードの単位" (通常はメソッド) をテストする代わりに、より高いレベルで実行されるユーザー全体またはシステム シナリオに焦点を当てます。この場合、たとえば、はるかに高いレベルでそれを取ることができ、DAL のどこかに CreateUser、UpdateUser、ReadUser と呼ばれるメソッドがあると仮定すると、テストするシナリオは次のようになります。 、ユーザー名を更新すると、ユーザーを読み取るときに名前を更新する必要があります」-データ、DAL、および場合によっては UI を含む完全なセットアップに対してシナリオを実行します。

その点から、 BDD + TDD に関する次のMSDN の記事は興味深いものでした。

2) メソッドをテスト可能にしたい場合は、何らかの状態を公開する必要があります。メソッドの主要部分は、コマンドの構築を中心に展開します。その方法を次のように概説できます。

* grab a connection
* create the parameters and types of the command
* fill in the parameters of the command from the object
* execute the command and clean up

これらのステップのほとんどを実際にテストできます。観察可能な状態はコマンド自体です。あなたはこれらの線に沿って何かを持つことができます:

public class UpdateUserCommandBuilder
{
   IConnectionConfiguration config;

   public void BuildAndExecute(User user)
   {
      var command = BuildCommand(user);
      ExecuteCommand(command);
   }

   public SqlCommand BuildCommand(User user)
   {
      var connection = config.GetConnection(); // so that you can mock it
      var command = new SqlCommand(...)

      command = CreateArguments(command); // you can verify that method now
      command = FillArguments(command, user); // and this one too

      return command;
   }
}

ここまでは説明しませんが、概要はアイデアを伝えていると思います。そのルートに進むと、ビルダーの手順を検証可能にするのに役立ちます。正しいコマンドが作成されたかどうかをアサートできます。これにはある程度の価値がありますが、コマンドの実行が成功したかどうかについては何もわかりません。そのため、これがテスト予算を使う価値があるかどうかを検討する価値があります。おそらく、DAL 全体を実行する高レベルの統合テストの方が経済的かもしれません。

お役に立てれば!

于 2012-05-05T18:51:16.620 に答える
1

メソッド宣言を次のように変更します。

public static void UpdateUser(User user, SqlConnection conn);

その後、構成済みの SQL 接続を渡すことができます。実際のアプリケーションでは、目的の接続について何がわかるかに依存しAppSettingsますが、テストでは、その接続に対して実行されたコマンドを記録できる偽の接続を与えます。次に、メソッドが格納されたクエリを正しく要求し、結果として正しいパラメーターを送信することを確認できます。

于 2012-05-05T18:57:36.373 に答える