単体テストを作成するときに何をテストするかをどのようにして知っていますか?[閉まっている]


127

C#を使用Userして、ユーザー名、パスワード、アクティブフラグ、名、姓、フルネームなどを持つクラスが必要です。

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


この投稿は、より広い質問の絞り込みに役立ちます。earnestengineer.blogspot.com / 2018/03 / これらのガイドライン
に従って

パスワードはプレーンテキストとして保存しないでください。
アンダーソン氏

回答:


131

これに対する多くの素晴らしい回答も私の質問にあります:「TDDの始まり-課題?ソリューション?推奨事項?

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

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

  • 新たにスタート。新しいコードを書くときだけテストを書くことを考えてください。これは、古いコードを再加工することも、まったく新しい機能にすることもできます。
  • 簡単に始めましょう。TDD風であるだけでなく、テストフレームワークに頭を悩ませることもありません。Debug.Assertは正常に動作します。出発点として使用してください。プロジェクトを台無しにしたり、依存関係を作成したりすることはありません。
  • ポジティブから始めましょう。あなたはあなたの技術を改善しようとしています、それについて気分が良いです。私は停滞していて自分たちをより良くするために新しいことを試みないことに満足している多くの開発者を見てきました。あなたは正しいことをしています。これを覚えておけば、あきらめないようにするのに役立ちます。
  • 挑戦の準備を始めてください。テストを始めるのはかなり難しいです。挑戦を期待しますが、覚えておいてください–挑戦は克服することができます。

期待することだけをテストする

発生する可能性のあるすべての問題を把握し、それをテストして修正するために常にそこに座っていたため、最初に本当の問題を抱えていました。これは頭​​痛への簡単な方法です。テストは実際のYAGNIプロセスでなければなりません。問題があることがわかっている場合は、テストを作成します。それ以外の場合は、気にしないでください。

1つのものだけをテストする

各テストケースでテストできるのは1つだけです。テストケース名に「and」が含まれていることに気付いた場合は、何か問題があります。

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


2
「問題があることがわかっている場合は、テストを作成します。そうでない場合は、気にしないでください。」これの言い方には反対だ。ユニットテストはすべての可能な実行パスをカバーするべきだという印象を受けました。
Corin Blaikie、2008

3
一部はそのようなことを主張するかもしれませんが、私は個人的には主張しません。私の頭痛の90%は、単に「すべて」を実行しようとすることから生じました。私はあなたが何が起こるか期待するためのテストを言います(それであなたはあなたが正しい値を取り戻していることを知っています)が、それをすべて理解しようとしないでください。YAGNI。
Rob Cooper

4
私も、「バグのテスト」アプローチを提唱しています。もし私たち全員が無限の時間と忍耐力を持っているなら、私たちは可能なすべての実行パスをテストします。しかし、そうではないので、それが最大の効果をもたらすであろうところにあなたの努力を費やさなければなりません。
シュヴェルン

63

言語ではなくコードをテストします。

次のような単体テスト:

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

コンパイラーを作成していて、instanceofメソッドが機能しない可能性がゼロでない場合にのみ役立ちます。

強制的に言語に依存できるものはテストしないでください。あなたの場合、私はあなたのauthenticateメソッドとsaveメソッドに焦点を当てます-そして、それらのフィールドのいずれかまたはすべてでnull値を正常に処理できることを確認するテストを書きます。


1
「フレームワークをテストしない」の良い点-これが初めてのときに私も思いついたことがあります。+1されました:)
Rob Cooper、

38

これは私を単体テストに連れて行ってくれて、とても幸せになりました

ユニットテストを開始しました。長い間、それを始めるのは良いことだと思っていましたが、どのように始めればいいのか、そして何をテストすればよいのかわかりませんでした。

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

支払い方法が非常に多かったので、コーディングを開始する方法がわかりませんでした。請求書は$ 100になる可能性がありますが、顧客は$ 99のみを転送しました。顧客に販売請求書を送信したが、その顧客からも購入した可能性があります。だからあなたは彼を300ドルで売ったが、あなたは100ドルで買った。残高を決済するために顧客に200ドルを支払うことを期待できます。また、500ドルで販売したが、顧客が250ドルしか支払わない場合はどうでしょうか。

だから私は多くの可能性を解決するために非常に複雑な問題を持っていました。

ここでユニットテストが役に立ちました。

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

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

テストの実行後、データベースに移動して、期待したものがそこにあったかどうかを再確認しました。

テストを書いた、支払い方法(BankHeaderクラスの一部)のコーディングを開始しました。コーディングでは、最初のテストに合格するためのコードに悩まされました。他のもっと複雑なシナリオについてはまだ考えていませんでした。

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

次に、2番目のテストの作成を開始しました。今回は支払い割引を扱います。テストを書いた後、割引をサポートするように支払い方法を変更しました。

支払い割引で正しさをテストすると同時に、単純な支払いもテストしました。もちろん、両方のテストに合格するはずです。

次に、より複雑なシナリオにたどり着きました。

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

2)そのシナリオのテストを書く

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

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);
    }

1
単体テストでバグを見つけました!あなたがそれらのいずれかで2を含むのではなく、この行を繰り返しますAssert.AreEqual(0, bankHeader.BankCashDetails[0].Payments[3].InvoiceHeader.Balance);
ライアンPeschel

2
あなたは言う:「テストが実行された後、私はデータベースに行き、私が期待したものがそこにあったかどうかを再確認します。」これは、システムのコンポーネント間の統合テストの良い例であり、単一のコードの単体テストではありません。
JTech 2017年

2
また、テストごとに複数のアサートのルールに違反しました。
Steve

13

それらが本当に取るに足らないものであれば、テストを気にしないでください。たとえば、このように実装されている場合。

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

逆に、(getter / setterでパスワードを暗号化および復号化するなど)巧妙な処理を行っている場合は、テストを行ってください。


10

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


6

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

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

コードの信頼性は、特に追加機能を追加するための変更が行われている間は、第一の目標です。私はテスト方法論にセッター/ゲッターを含めたことで解雇された人を誰も知らないが、私が知っていた、または思い出せる簡単なセット/ゲットラッパーであるメソッドをテストしたいと思っていた人が確かにいるが、それはなかった長いケース。

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

2人のチームメイトは、セット/ゲットが失敗してユニットテストでカバーされないロジックを含むようにモーフィングされたときに、誰がボールを落としてユニットテストに失敗したかについて議論します。最初にset / getsを作成したチームメイトは、単純なset / getsに対してテストが初日から実装されていれば、このクリーンから抜け出すのが簡単になります。

私の意見では、ユニットテストですべてのメソッドをカバーする数分の「無駄な」時間は、たとえ些細なものであっても、道のりの頭痛やお金の損失/ビジネスの評判、そして誰かの仕事の損失を節約できるかもしれません。

そして、単純なメソッドを単体テストでラップしたという事実は、ジュニアチームメイトが単純なメソッドを重要なメソッドに変更し、テストを更新するように促すときに、欠陥が含まれていたので誰も問題を抱えていないように見えるかもしれません。生産に達することから。

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


4

別の正解。これは、Ron Jeffriesからのものだと思います。

作業したいコードのみをテストします。


3

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

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


3

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

私は通常、クラスに期待する動作を検証する非常に単純なテストを多数記述します。2つの数値を加算するような単純なものであっても。簡単なテストを書くことと、コードのいくつかの行を書くことの間で多くのことを切り替えます。これは、自分が思いもよらないことを壊してしまうことを恐れずに、コードを変更できるからです。


KISSの原則をうまく説明してくれてうれしいです。私は文字通り2〜3行のコードのようなテスト、実際には小さく単純なテストを頻繁に行っています。簡単に壊れて壊れにくい:) +1された
Rob Cooper

3

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

一般的に、広範囲にわたるユーザーテストを書くことは片側にあり、疲れることに気づきます。一方、アプリケーションの動作に関する貴重な洞察を常に提供し、簡単な(そして誤った)仮定(たとえば、ユーザー名の長さが常に1000文字未満になる)を捨てるのに役立ちます。


3

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


2

ゲッターとセッターのためのユニットテストを書くのに害はありません。現時点では、内部でフィールドの取得/設定を行っているだけかもしれませんが、将来的には検証ロジックや、テストする必要のあるプロパティ間の依存関係が存在する可能性があります。あなたがそれについて考えている間に今それを書いて、その時が来たらそれを改造することを覚えていることは今より簡単です。


まあ、ゲッター/セッターにユニットテストが必要な場合は、それらに関連付けられたロジックが必要です。つまり、ロジックを内部に記述する必要があります。ロジックがない場合は、ユニットテストを記述する必要はありません。
ポップカタリン

2
彼のポイントは、後でロジックが追加される可能性があるということです。
LegendLength 2009年

2

一般に、メソッドが特定の値に対してのみ定義されている場合は、許容できる範囲の境界を越えて値をテストします。言い換えれば、あなたの方法は、行うことになって、何ないことを確認してください何よりますが。失敗するときは早く失敗したいので、これは重要です。

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

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


2

壊れる可能性があると思ったら、テストを書いてください。私は通常、setter / getterをテストしませんが、姓と名を連結するUser.Nameの1つを作成すると言うと、誰かが姓と名の順序を変更した場合、少なくとも彼は知っています。彼はテストされた何かを変えました。


2

正解は「壊れる可能性のあるものをすべてテストする」です。プロパティが壊れないことが確実な場合は、テストしないでください。

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


1

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


1

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


1

ゲッターとセッターをテストします。コードを書いている人によっては、getter / setterメソッドの意味を変更する人もいます。ゲッターメソッドの一部として、変数の初期化とその他の検証を見てきました。この種のものをテストするには、そのコードを明示的にカバーする単体テストが必要です。


1

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

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


1

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

適用される単純な整数の場合-整数の代わりにlongを渡すとどうなりますか?それがあなたがUTを書く理由です:)


1

プロパティの実際の設定はテストしません。これらのプロパティがコンシューマーによってどのように入力されるか、およびそれらに何が入力されるかについて、私はもっと心配します。どのようなテストでも、リスクとテストの時間/コストを比較検討する必要があります。


1

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

プロパティが取るに足らないもので、誰かがバグを導入する可能性が低い場合は、それらを単体テストしない方が安全です。

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


1

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

後でテストを書くのはもっと大変ですが、実行可能です。

これが私があなたの立場でやることです:

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

これにより、リグレッションに対する適切なバッファーとして機能するユニットテストの優れたワーキングセットが得られます。

このアプローチの唯一の問題は、コードを設計する必要があることですでテストにする必要があることです。早い段階でカップリングのミスをした場合、高いカバレッジを簡単に得ることができません。

これが、コードを書く前にテストを書くことが本当に重要である理由です。疎結合のコードを書くことを強制します。


1

明らかに機能している(定型)コードはテストしないでください。したがって、セッターとゲッターが単に "propertyvalue = value"と "return propertyvalue"の場合、それをテストしても意味がありません。


1

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

これらの各テストでは、プロパティのパラメーターのセットを指定し、受け入れ可能なプロパティと受け入れられないプロパティの両方を定義して、呼び出しが期待どおりに戻る/失敗するようにします。

また、SQLインジェクションの例として、セキュリティの問題点を認識し、これらをテストする必要があります。

そのため、プロパティのテストについて心配する必要があります。


1

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


1

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()
        {

        }
    }

テストを記述して、何かを行うために記述したコードを検証します。物事のコレクションを繰り返し処理し、それぞれについて何かを変更する場合は、同じことを行うテストと実際に発生したアサートを記述します。

実行できるアプローチは他にもたくさんあります。つまり、Behavoir Driven Development(BDD)はもっと複雑で、ユニットテストのスキルから始めるのに最適な場所ではありません。

ですから、話の教訓は、あなたが心配するかもしれないことを何でもすることを何でもテストし、ユニットテストがサイズの小さい特定のものをテストし続けることです、多くのテストが良いです。

ビジネスロジックをユーザーインターフェースレイヤーの外側に置いて、テストを簡単に記述できるようにしてください。

TestDriven.NetまたはReSharperをお勧めします。どちらもVisual Studioに簡単に統合できます。


1

AuthenticateメソッドとSaveメソッドに複数のテストを記述することをお勧めします。成功例(すべてのパラメーターが提供され、すべてのスペルが正しいなど)に加えて、さまざまな失敗例(パラメーターが正しくないか欠落している、該当する場合はデータベース接続が利用できないなど)についてテストすることをお勧めします。参考として、NUnitを使用したC#の実用的なユニットテストをお勧めします

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


1

コードでテストが必要な場所を正確に推測することは可能ですが、私は通常、この推測を裏付けるメトリックが必要だと思います。私の見解では、ユニットテストはコードカバレッジメトリックと連動しています。

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

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

「ガベージイン」をテストすることを忘れないでください!

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

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


1

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

ソフトウェア開発者がテスト駆動開発を行うときに忘れてしまうことの1つは、私たちの行動の背後にある目的です。実稼働コードがすでに配置された後にユニットテストが記述されている場合、テストの値は非常に低くなります(完全に失われるわけではありません)。

ユニットテストの真の精神では、これらのテストは主にコードを「テスト」するためのものではありません。または、90%-100%のコードカバレッジを向上させます。これらはすべて、最初にテストを記述することの利点です。大きな見返りは、TDDの自然なプロセスにより、プロダクションコードの終わりが大幅に改善されることです。

この考えをよりよく伝えるために、以下の資料が参考になるかもしれません。

単体テストの欠陥理論
意図的なソフトウェア開発

より多くの単体テストを作成することが、より高品質の製品を得るのに役立つと私たちが感じた場合、テスト駆動開発の貨物カルトに苦しんでいる可能性があります。


実稼働コードがすでに導入されていると、ユニットテストには価値がないという主張に同意しません。このようなアサーションは、本番環境で見つかったエラー状態を複製したり、以前の開発者やチームから継承されたコードを理解したりする際の有用性を考慮していません。
スコットローレンス

間違って遭遇したかもしれません。量産コードが導入された後は、単体テストに価値がないという意味ではありませんでした。ただし、その価値は下がります。単体テストの最大のメリットは、本番環境での開発を推進させるときに発生する固有の魔法です。
スコットサード
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.