単体テストを作成するときに何をテストすべきかをどうやって知ることができますか?[閉まっている]

StackOverflow https://stackoverflow.com/questions/62625

  •  09-06-2019
  •  | 
  •  

質問

C# を使用するには、というクラスが必要です。 User ユーザー名、パスワード、アクティブなフラグ、名、姓、フルネームなどが含まれます。

方法があるはずです 認証する そして 保存 ユーザー。メソッドのテストを書くだけですか?また、プロパティは .Net のゲッターとセッターなので、テストについて心配する必要はありますか?

役に立ちましたか?

解決

これに対する多くの素晴らしい回答が私の質問にもあります。」TDD を始める - 課題はありますか?解決策は?おすすめは?"

私のものもご覧になることをお勧めします ブログ投稿 (これは私の質問に一部影響を受けました)、それに関していくつかの良いフィードバックを受け取りました。つまり:

どこから始めればよいかわかりません?

  • 新たに始めてください。新しいコードを書いているときにのみテストを作成することを考えてください。これは、古いコードの再ワーキング、または完全に新しい機能です。
  • シンプルに始めましょう。走り去り、TDD風だけでなく、テストフレームワークの周りに頭を獲得しようとしないでください。Debug.Assert は正常に動作します。出発点として使用してください。それはあなたのプロジェクトを台無しにしたり、依存関係を作成したりしません。
  • ポジティブにスタートしましょう。あなたは自分の工芸を改善しようとしています、それについて気分が良くなります。私はそこにたくさんの開発者を見てきました。それは喜んで停滞し、自分自身をより良くするために新しいことを試してみません。あなたは正しいことをしています、これを覚えておいてください、そしてそれはあなたがあきらめるのを止めるのに役立ちます。
  • 挑戦の準備を始めましょう。テストを開始するのは非常に困難です。挑戦を期待しますが、覚えておいてください - 課題は克服できます。

期待するものだけをテストする

私が最初に始めたとき、私は本当の問題を抱えていました。なぜなら、私は常にそこに座っていたので、発生する可能性のあるすべての問題を把握しようとしていて、それをテストして修正しようとしていたからです。これは頭​​痛への早道です。テストは実際のYagniプロセスである必要があります。問題があることがわかっている場合は、テストを書いてください。それ以外の場合は、気にしないでください。

1 つのことだけをテストする

各テストケースは、1つのことのみをテストする必要があります。テストケース名に「アンド」を入れていることに気付いた場合、何か間違ったことをしています。

これで「ゲッターとセッター」から先に進むことができることを願っています:)

他のヒント

言語ではなくコードをテストしてください。

次のような単体テスト:

Integer i = new Integer(7);
assert (i.instanceOf(integer));

これは、コンパイラを作成していて、コンパイラがコンパイラに影響を与える可能性がゼロではない場合にのみ役立ちます。 instanceof 方法が機能していません。

言語に依存して適用できるものはテストしないでください。あなたの場合、私は認証メソッドと保存メソッドに焦点を当て、それらのフィールドのいずれかまたはすべてで null 値を適切に処理できることを確認するテストを作成します。

これにより単体テストを始めることができ、とても満足しました

単体テストを始めたばかりです。長い間、それを始めるべきだとは思っていましたが、どうやって始めればよいのか、さらに重要なことに何をテストすればよいのかわかりませんでした。

次に、会計プログラムの重要なコードを書き直す必要がありました。この部分はさまざまなシナリオが関係するため、非常に複雑でした。私が話しているのは、会計システムにすでに入力されている売上や購買の請求書を支払う方法です。

支払いオプションが多すぎて、どうやってコーディングを始めればよいのかわかりませんでした。請求書は 100 ドルですが、顧客が送金したのは 99 ドルだけです。もしかしたら、顧客に売上請求書を送ったことがあるかもしれませんが、その顧客から購入したこともあります。つまり、あなたは彼を 300 ドルで売りましたが、あなたは 100 ドルで買いました。顧客は残高を決済するために 200 ドルを支払うことが期待できます。そして、あなたが 500 ドルで販売したのに、顧客が支払ったのが 250 ドルだった場合はどうなるでしょうか?

そのため、あるシナリオは完璧に機能しても、別の種類の請求書と支払いの組み合わせでは間違っている可能性があるため、解決する必要がある非常に複雑な問題がありました。

ここで単体テストが役に立ちます。

私は、販売と購入の両方の請求書のリストを作成するメソッドを (テスト コード内で) 書き始めました。次に、実際の支払いを作成する 2 番目のメソッドを作成しました。通常、ユーザーはユーザー インターフェイスを通じてその情報を入力します。

次に、最初の TestMethod を作成し、支払い割引を行わない 1 つの請求書の非常に単純な支払いをテストしました。システム内のすべてのアクションは、銀行支払いがデータベースに保存されるときに発生します。ご覧のとおり、請求書を作成し、支払い (銀行取引) を作成し、取引をディスクに保存しました。私のアサーションでは、銀行取引とリンクされた請求書に含まれる正しい数値を記載しました。取引後の請求書の支払い回数、支払い金額、割引額、残高を確認します。

テストの実行後、データベースにアクセスして、期待したものが存在するかどうかを再確認します。

私はテストを書き、支払いメソッド (BankHeader クラスの一部) のコーディングを開始しました。コーディングでは、最初のテストに合格するためのコードだけを考えました。他のより複雑なシナリオについてはまだ考えていませんでした。

最初のテストを実行し、テストが合格するまで小さなバグを修正しました。

次に、2 番目のテストを書き始めました。今回は支払い割引を使用して作業しました。テストを作成した後、割引をサポートするために支払い方法を変更しました。

支払い割引が正しいかどうかをテストする一方で、簡単な支払いもテストしました。もちろん両方のテストに合格する必要があります。

次に、より複雑なシナリオに取り組みました。

1) 新しいシナリオを考える

2) そのシナリオのテストを作成します

3) その 1 つのテストを実行して、合格するかどうかを確認します。

4) そうでない場合は、コードが合格するまでデバッグして修正します。

5) コードを変更している間、すべてのテストを実行し続けました。

このようにして、非常に複雑な支払い方法を作成することができました。単体テストがなければ、どうやってコーディングを始めればよいのかわかりませんでした。問題が圧倒的に見えました。テストでは、単純な方法から始めて、より単純なシナリオでも機能することを保証しながら段階的に拡張することができました。

単体テストを使用することで、コーディングの時間が数日 (または数週間) 節約され、メソッドの正確さが多かれ少なかれ保証されていると確信しています。

後で新しいシナリオを思いついた場合は、それをテストに追加して、それが機能するかどうかを確認するだけです。そうでない場合は、コードを変更しても、他のシナリオが引き続き正しく動作することを確認できます。これにより、メンテナンスとバグ修正の段階で何日も費やすことができます。

はい、ユーザーが思いつかないことをしたり、ユーザーの実行を妨げたりした場合、テスト済みのコードでもバグが存在する可能性があります。

以下は、支払い方法をテストするために作成したテストのほんの一部です。

public class TestPayments
{
    InvoiceDiaryHeader invoiceHeader = null;
    InvoiceDiaryDetail invoiceDetail = null;
    BankCashDiaryHeader bankHeader = null;
    BankCashDiaryDetail bankDetail = null;



    public InvoiceDiaryHeader CreateSales(string amountIncVat, bool sales, int invoiceNumber, string date)
    {
        ......
        ......
    }

    public BankCashDiaryHeader CreateMultiplePayments(IList<InvoiceDiaryHeader> invoices, int headerNumber, decimal amount, decimal discount)
    {
       ......
       ......
       ......
    }


    [TestMethod]
    public void TestSingleSalesPaymentNoDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 1, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 1, 119.00M, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(119M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(0M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSingleSalesPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 2, "01-09-2008"));
        bankHeader = CreateMultiplePayments(list, 2, 118.00M, 1M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(1, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(1M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
    }

    [TestMethod]
    [ExpectedException(typeof(ApplicationException))]
    public void TestDuplicateInvoiceNumber()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("100", true, 2, "01-09-2008"));
        list.Add(CreateSales("200", true, 2, "01-09-2008"));

        bankHeader = CreateMultiplePayments(list, 3, 300, 0);
        bankHeader.Save();
        Assert.Fail("expected an ApplicationException");
    }

    [TestMethod]
    public void TestMultipleSalesPaymentWithPaymentDiscount()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("119", true, 11, "01-09-2008"));
        list.Add(CreateSales("400", true, 12, "02-09-2008"));
        list.Add(CreateSales("600", true, 13, "03-09-2008"));
        list.Add(CreateSales("25,40", true, 14, "04-09-2008"));

        bankHeader = CreateMultiplePayments(list, 5, 1144.00M, 0.40M);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(4, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(118.60M, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(400, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(600, bankHeader.BankCashDetails[0].Payments[2].PaymentAmount);
        Assert.AreEqual(25.40M, bankHeader.BankCashDetails[0].Payments[3].PaymentAmount);

        Assert.AreEqual(0.40M, bankHeader.BankCashDetails[0].Payments[0].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].PaymentDiscount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].PaymentDiscount);

        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[2].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
    }

    [TestMethod]
    public void TestSettlement()
    {
        IList<InvoiceDiaryHeader> list = new List<InvoiceDiaryHeader>();
        list.Add(CreateSales("300", true, 43, "01-09-2008")); //Sales
        list.Add(CreateSales("100", false, 6453, "02-09-2008")); //Purchase

        bankHeader = CreateMultiplePayments(list, 22, 200, 0);
        bankHeader.Save();

        Assert.AreEqual(1, bankHeader.BankCashDetails.Count);
        Assert.AreEqual(2, bankHeader.BankCashDetails[0].Payments.Count);
        Assert.AreEqual(300, bankHeader.BankCashDetails[0].Payments[0].PaymentAmount);
        Assert.AreEqual(-100, bankHeader.BankCashDetails[0].Payments[1].PaymentAmount);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[0].InvoiceHeader.Balance);
        Assert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[1].InvoiceHeader.Balance);
    }

本当に些細な問題であれば、わざわざテストする必要はありません。たとえば、次のように実装されているとします。

public class User
{
    public string Username { get; set; }
    public string Password { get; set; }
}

一方、何か賢いことを行っている場合 (ゲッター/セッターでのパスワードの暗号化と復号化など)、テストを行ってください。

ルールは、作成したロジックをすべてテストする必要があるということです。ゲッターとセッターに特定の機能を実装している場合は、テストする価値があると思います。一部のプライベート フィールドに値を割り当てるだけであれば、気にする必要はありません。

この質問は、どのメソッドがテストされ、どのメソッドがテストされないかをどこで線引きするかという問題のようです。

値の割り当てのためのセッターとゲッターは、一貫性と将来の成長を念頭に置いて作成されており、将来的にはセッター/ゲッターがより複雑な操作に進化する可能性があると予測しています。一貫性と将来の成長のためにも、これらのメソッドの単体テストを導入することは理にかなっています。

特に追加機能を追加するために変更が行われている間のコードの信頼性が主な目標です。テスト手法にセッター/ゲッターを含めたために解雇された人を私は知りませんが、最後に知っていた、または思い出せるメソッドが単純な set/get ラッパーだったが、そうではなかったメソッドをテストしておけばよかったと思っている人がいることは確かです。もっと長い場合。

おそらく、チームの別のメンバーが set/get メソッドを拡張して、テストが必要なロジックを含めたものの、その後テストを作成しなかった可能性があります。しかし、コードがこれらのメソッドを呼び出しているため、それらが変更されて詳細なテストが必要であることに気づいていません。開発や QA で行うテストでは欠陥が発生しませんが、リリース初日の実際のビジネス データでは欠陥が発生します。それを引き起こします。

2 人のチームメイトは、失敗する可能性があるが単体テストでカバーされないロジックを含むようにセットまたはモーフィングが変更されたときに、誰がボールを落として単体テストを入れなかったのかについて議論します。最初からセット/ゲットを作成したチームメイトは、テストが初日から単純なセット/ゲットに実装されていれば、このクリーンな状況から抜け出すのが容易になります。

私の意見は、たとえ些細なものであっても、単体テストですべてのメソッドをカバーする数分間の「無駄な」時間を使えば、将来何日も頭痛に悩まされることや、ビジネスの金銭や評判の損失、そして誰かの職の喪失を避けることができるかもしれない、というものです。

そして、あなたが自明なメソッドを単体テストでラップしたという事実は、その後輩のチームメイトが自明なメソッドを非自明なメソッドに変更してテストを更新するよう促すときに目につくかもしれません。そして今では、欠陥は封じ込められているので誰も困っていません。生産に到達するまで。

私たちのコーディング方法とコードからわかる規律は、他の人を助けることができます。

もう一つの標準的な答え。これはロン・ジェフリーズ氏の言葉だと思います。

動作させたいコードのみをテストしてください。

定型コードのテストは時間の無駄ですが、Slavo 氏が言うように、ゲッター/セッターに副作用を追加する場合は、その機能に付随するテストを作成する必要があります。

テスト駆動開発を行っている場合は、最初にコントラクト (インターフェイスなど) を作成し、次に、期待される結果/動作を文書化するそのインターフェイスを実行するテストを作成する必要があります。 それから 単体テストのコードには触れずに、メソッド自体を記述します。最後に、コード カバレッジ ツールを入手し、テストがコード内のすべてのロジック パスを実行していることを確認します。

プライベート フィールドを設定する以外に特別な動作を持たないゲッターやセッターのような本当に単純なコードは、テストするには過剰です。3.0 の C# には、プライベート フィールドをコンパイラが処理するための構文糖も含まれているため、それをプログラムする必要はありません。

私は通常、クラスに期待される動作を検証する非常に単純なテストをたくさん書きます。たとえそれが2つの数字を足すような単純なことであっても。私は、単純なテストを書くことと、数行のコードを書くことを頻繁に切り替えます。その理由は、考えてもいなかったものを壊すことを恐れることなく、コードを変更できるからです。

すべてをテストする必要があります。現時点ではゲッターとセッターがありますが、いつか検証などを行うためにそれらを多少変更するかもしれません。今日作成したテストは、明日、すべてが通常どおり動作することを確認するために使用されます。テストを書くときは、「今のところそれは些細なことだ」などの考慮事項は忘れるべきです。アジャイルまたはテスト駆動のコンテキストでは、将来のリファクタリングを想定してテストする必要があります。また、非常に長い文字列やその他の「不適切な」コンテンツなど、非常に奇妙な値を入力しようとしましたか?まあ、そうすべきです...コードが将来どれほど悪用される可能性があるかを決して想定しないでください。

一般に、広範なユーザー テストを作成するのは、一方では大変なことだと思います。しかしその一方で、アプリケーションがどのように動作するべきかについて常に貴重な洞察を与え、安易な (そして誤った) 仮定 (次のような) を捨てるのに役立ちます。ユーザー名の長さは常に 1000 文字未満になります)。

最終的にツールキットやオープン ソース タイプのプロジェクトに含まれる可能性がある単純なモジュールの場合は、簡単なゲッターとセッターを含めて、できる限りテストする必要があります。覚えておいていただきたいのは、特定のモジュールを作成するときに単体テストを生成するのは非常にシンプルで簡単であるということです。ゲッターとセッターの追加は最小限のコードであり、あまり考えずに処理できます。ただし、コードをより大規模なシステムに配置すると、この余分な作業により、基底クラスの型変更など、基礎となるシステムの変更から保護できます。完全な回帰を実現するには、すべてをテストすることが最善の方法です。

ゲッターとセッターの単体テストを作成することに問題はありません。現時点では、フィールドの取得/設定を内部で実行しているだけかもしれませんが、将来的には、検証ロジックやプロパティ間の依存関係をテストする必要がある可能性があります。それについて考えている間に今書いて、その時が来たときにそれを後付けすることを忘れない方が簡単です。

一般に、メソッドが特定の値に対してのみ定義されている場合は、値をテストします。 オーバー 許容される範囲。言い換えれば、メソッドが本来の動作を確実に行うようにすることです。 しかしそれ以上は何もない. 。失敗するときは早めに失敗したいので、これは重要です。

継承階層では、必ずテストしてください。 LSP コンプライアンス。

後で検証を行う予定がない限り、デフォルトのゲッターとセッターをテストすることは、私にとってはあまり役に立たないようです。

アジャイル開発のコンテキストにおける単体テストについては理解していますが、マイク、はい、ゲッターとセッターをテストする必要があります (公開されていると仮定して)。単体テストの全体的な概念は、ソフトウェア ユニット (この場合はクラス) をテストすることです。 ブラックボックス. 。ゲッターとセッターは外部から見えるため、認証と保存とともにテストする必要があります。

Authenticate メソッドと Save メソッドがプロパティを使用する場合、テストは間接的にプロパティに影響します。プロパティがデータへのアクセスを提供するだけである限り、明示的なテストは必要ありません (100% カバレッジを目指す場合を除く)。

ゲッターとセッターをテストしてみます。コードを作成する人に応じて、ゲッター/セッター メソッドの意味を変更する人もいます。ゲッター メソッドの一部として変数の初期化やその他の検証が行われることを見てきました。この種のことをテストするには、そのコードを明示的にカバーする単体テストが必要になります。

個人的には、「壊れる可能性のあるものはすべてテストする」と思いますが、単純なゲッター (またはさらに優れた自動プロパティ) は壊れません。私は単純な return ステートメントが失敗したことがないため、テストを行ったことはありません。ゲッターの内部に計算やその他の形式のステートメントが含まれている場合は、それらのテストを確実に追加します。

個人的に私が使っているのは モク モック オブジェクト フレームワークとして作成し、オブジェクトが周囲のオブジェクトを適切に呼び出すことを確認します。

クラスのすべてのメソッドの実行を UT でカバーし、メソッドの戻り値を確認する必要があります。これには、特にメンバー (プロパティ) が初期化中に大量のメモリ割り当てを必要とする複雑なクラスの場合のゲッターとセッターが含まれます。たとえば非常に大きな文字列(またはギリシャ文字を含むもの)を使用してセッターを呼び出し、結果が正しいことを確認します(切り捨てられていない、エンコードが適切であるなど)。

単純な整数の場合も同様です。整数の代わりにlongを渡すとどうなりますか?それが UT を書く理由です:)

実際のプロパティの設定はテストしません。私は、これらのプロパティが消費者によってどのように設定されるか、またそれらのプロパティに何が設定されるかについてより関心があります。どのようなテストを行う場合でも、テストにかかる時間やコストとリスクを比較検討する必要があります。

可能な限り単体テストを使用して、「重要なコードのすべてのブロック」をテストする必要があります。

プロパティが些細なもので、誰かがそのプロパティにバグを持ち込む可能性が低い場合は、単体テストを行わなくても安全です。

Authenticate() メソッドと Save() メソッドは、テストに適した候補のように見えます。

理想的には、クラスを作成しているときに単体テストを実行する必要があります。これは、テスト駆動開発を使用するときに行うべき方法です。各関数ポイントを実装するときにテストを追加し、エッジケースもテストでカバーしていることを確認します。

後でテストを書くのははるかに面倒ですが、実行可能です。

私があなたの立場ならこうします:

  1. コア機能をテストする基本的なテスト セットを作成します。
  2. NCover を入手してテストで実行します。この時点で、テスト カバレッジはおそらく 50% 程度になるでしょう。
  3. 約 80% ~ 90% をカバーするまで、エッジケースをカバーするテストを追加し続けます。

これにより、回帰に対する適切なバッファとして機能する、単体テストの適切な作業セットが得られます。

このアプローチの唯一の問題は、コードを次のようにする必要があることです。 設計 この方法でテストできるようになります。早い段階でカップリングを間違えると、高いカバレッジを簡単に得ることができなくなります。

このため、コードを記述する前にテストを作成することが非常に重要です。疎結合なコードを記述する必要があります。

明らかに機能する (ボイラープレート) コードをテストしないでください。したがって、セッターとゲッターが単に「propertyvalue = value」および「return propertyvalue」である場合、それをテストするのは意味がありません。

get / set であっても、実装方法によっては奇妙な結果が生じる可能性があるため、メソッドとして扱う必要があります。

これらの各テストでは、プロパティのパラメーターのセットを指定し、呼び出しが期待どおりに返されるか失敗するかを確認するために、許容されるプロパティと許容できないプロパティの両方を定義する必要があります。

また、SQL インジェクションなどのセキュリティ上の注意点にも注意し、それらをテストする必要があります。

したがって、プロパティのテストについて心配する必要はありません。

単純な操作しか行わないゲッターとセッターをテストするのは愚かだと思います。個人的に、私は使用パターンをカバーするために複雑な単体テストを作成しません。通常の実行動作と、考えられる限りのエラーケースを確実に処理できるように、十分なテストを作成するようにしています。バグレポートへの対応として、さらに単体テストを作成する予定です。コードが要件を満たしていることを確認し、将来の変更を容易にするために単体テストを使用します。何かを壊すとテストが失敗するとわかっていると、コードを変更する意欲がさらに高まります。

GUI インターフェイスの外部でテスト可能なコードを作成する場合は、すべてテストを作成します。

通常、ビジネス ロジックを含むロジックを作成する場合は、別の層またはビジネス ロジック層内に配置します。

そうすれば、何かを行うためのテストを書くのは簡単になります。

最初のパスは、「ビジネス ロジック レイヤー」内の各パブリック メソッドの単体テストを作成します。

このようなクラスがあったとします。

   public class AccountService
    {
        public void DebitAccount(int accountNumber, double amount)
        {

        }

        public void CreditAccount(int accountNumber, double amount)
        {

        }

        public void CloseAccount(int accountNumber)
        {

        }
    }

これらのアクションを実行する必要があるとわかっていて、コードを作成する前に最初に行うことは、単体テストの作成を開始することです。

   [TestFixture]
    public class AccountServiceTests
    {
        [Test]
        public void DebitAccountTest()
        {

        }

        [Test]
        public void CreditAccountTest()
        {

        }

        [Test]
        public void CloseAccountTest()
        {

        }
    }

何かを実行するために作成したコードを検証するテストを作成します。物事のコレクションを反復処理し、それぞれについて何かを変更する場合は、同じことを行うテストを作成し、実際に起こったことをアサートします。

他にも利用できるアプローチはたくさんあります。その 1 つは、動作駆動開発 (BDD) ですが、これはより複雑であり、単体テストのスキルを始めるのには適していません。

したがって、この話の教訓は、心配する可能性のあるものはすべてテストし、単体テストはサイズの小さい特定のものをテストし続け、テストはたくさん行うのが良いということです。

ビジネス ロジックをユーザー インターフェイス層の外側に置いて、テストを簡単に作成できるようにすれば、問題はありません。

お勧めします TestDriven.Net または リシャープ どちらも Visual Studio に簡単に統合できるためです。

壊れる可能性があると思われる場合は、テストを作成してください。私は通常、セッター/ゲッターをテストしませんが、姓と名を連結する User.Name 用のテストを作成するとします。誰かが姓と名の順序を変更した場合、少なくとも彼はそれを知ることができるようにテストを作成します。彼はテストされたものを変更しました。

標準的な答えは、「おそらく壊れる可能性のあるものをテストする」ことです。プロパティが壊れないと確信している場合は、テストしないでください。

そして、何かが壊れていることが判明したら (バグを見つけた場合)、明らかにそれをテストする必要があることを意味します。バグを再現するテストを作成し、失敗するのを確認してからバグを修正し、テストが成功するのを確認します。

Authenticate メソッドと Save メソッドに対して複数のテストを作成することをお勧めします。成功ケース (すべてのパラメータが指定されている、すべてのスペルが正しいなど) に加えて、さまざまな失敗ケース (パラメータが間違っているか欠落している、該当する場合はデータベース接続が利用できないなど) についてもテストすることをお勧めします。お勧めします NUnit を使用した C# でのプラグマティックな単体テスト 参考として。

他の人が述べているように、ゲッターとセッターに条件付きロジックがない限り、ゲッターとセッターの単体テストは過剰です。

コードのどこでテストが必要かを正確に推測することは可能ですが、一般的にはこの推測を裏付けるメトリクスが必要だと思います。私の考えでは、単体テストはコードカバレッジの指標と密接に関係しています。

多くのテストが含まれるコードですが、一部の範囲は十分にテストされていません。とはいえ、カバレッジが 100% であっても、境界やエラーのケースをテストしていないコードも優れたものではありません。

高いカバレッジ (90% 以上) と可変入力データの間のバランスが必要です。

「ゴミが入っているかどうか」をテストすることを忘れないでください。

また、単体テストは、障害をチェックしない限り単体テストではありません。アサートのない単体テスト、または既知の例外がマークされている単体テストは、実行時にコードが終了しないことをテストするだけです。

テストが常に失敗または予期しない/不要なデータを報告するようにテストを設計する必要があります。

それは私たちのコードをより良くします...期間!

私たちソフトウェア開発者がテスト駆動開発を行うときに忘れていることの 1 つは、自分たちの行動の背後にある目的です。製品コードがすでに配置された後に単体テストを作成すると、テストの価値は大幅に低下します (ただし、完全に失われるわけではありません)。

単体テストの真の精神において、これらのテストは次のとおりです。 ない 主にコードをさらに「テスト」するためにあります。またはコード カバレッジを 90% ~ 100% 向上させることもできます。これらはすべてです フリンジベネフィット 最初にテストを書くこと。大きな成果は、TDD の自然なプロセスにより、本番コードの最終部分がはるかに適切に記述されることです。

この考えをよりよく伝えるために、以下を読むと役立つかもしれません。

単体テストの欠陥のある理論
目的を持ったソフトウェア開発

書くという行為が、 さらに多くの単体テスト それは私たちがより高品質の製品を得るのに役立つものですが、その場合、私たちは次のような問題に苦しんでいる可能性があります カーゴカルト テスト駆動開発の。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top