web-dev-qa-db-ja.com

ユニットテストは、ビジネスロジックが変更されたときに失敗した場合、脆弱と見なされますか?

以下のコードをご覧ください。それは女性の性別を持つ人が申し出の資格があるかどうかを確認するためにテストします1:

[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id,"Offer1");
    Assert.False(offer1.IsEligible(person));
}

この単体テストは成功しました。ただし、今後「Offer1」を女性に提供すると失敗します。

言うことは許容されますか?オファー1を取り巻くビジネスロジックが変更された場合、単体テストも変更する必要があります。場合によっては(オファーによっては)、データベース内のビジネスロジックが次のように変更されることに注意してください。

update Offers set Gender='M' where offer=1;

そして、いくつかのケースでは、このようなドメインモデルでは:

if (Gender=Gender.Male)
{
  //do something
}

また、背後にあるドメインロジックが定期的に変更を提供する場合とそうでない場合があることに注意してください。

27
w0051977

これは通常の意味では脆くない。単体テストは、テスト中の動作に影響を与えない実装の変更が原因で壊れた場合、脆弱と見なされます。しかし、ビジネスロジック自体が変更された場合、このロジックのテストは想定で破られます。

そうは言っても、ビジネスロジックが実際に頻繁に変更される場合、単体テストに期待値をハードコードすることはおそらく適切ではありません。代わりに、データベースの構成が期待どおりにオファーに影響するかどうかをテストできます。

テストの名前Returns False When Given A Person With A Gender Of Femaleはビジネスルールを記述していません。ビジネスルールはOffers Applicable to M should not be applied to persons of gender F

したがって、ifオファーがタイプMの個人にのみ適用可能であると定義されていることを確認するテストを作成すると、タイプFの個人は適格として示されません。このテストは、特定のオファーの構成が変更された場合でもロジックが機能することを確認します。

77
JacquesB

プロパティが運用データベース(またはテスト用のクローン)で定義されている場合、これは 単体テスト ではありません。単体テストは作業単位をチェックし、特定の外部状態が機能することを要求しません。これは、データベースで_Offer1_が男性のみのオファーであると定義されていることを前提としています。それが外部状態です。したがって、これは 統合テスト 、具体的には システム または 受け入れ テストの詳細です。受け入れテストはスクリプト化されていないことが多いことに注意してください(テストフレームワークでは実行されず、人間が手動で実行します)。

プロパティがifステートメントを使用してドメインモデルで定義されている場合、同じテストが単体テストになります。そして、それはもろいかもしれません。しかし、実際の問題は、コードがもろいということです。一般的なルールとして、ビジネスの振る舞いがハードコードされているよりも構成可能である場合、コードはより回復力があります。小さなコーディングエラーを修正するためのRush展開はまれであるためです。しかし、予告なしに変化するビジネス要件は、火曜日(毎週発生する何か)です。

単体テストフレームワークを使用してテストを実行している可能性があります。ただし、単体テストフレームワークは単体テストの実行に限定されません。統合テストも実行できます。

単体テストを作成している場合は、データベースの状態に依存せずに、personと_offer1_の両方をゼロから作成します。何かのようなもの

_[Fact]
public void ReturnsFalseWhenGivenAPersonWithAGenderOfFemale()
{
    var personId = Guid.NewGuid();
    var gender = "F";
    var person = new Person(personId, gender);

    var id = Guid.NewGuid();
    var offer1 = new Offer1(id, "ReturnsFalseWhenGivenAPersonWithAGenderOfFemale");
    offer1.markLimitedToGender("M");

    Assert.False(offer1.IsEligible(person));
}
_

これはビジネスロジックに基づいて変化しないことに注意してください。 _offer1_が女性を拒否するとは主張していません。それは_offer1_を女性を拒否する申し出のタイプにしています。

テストの一部としてデータベースを作成して構成する場合があります。 C#では、NUnitを使用して、またはJavaのJUnitでは、Setupメソッドでデータベースを設定します。おそらくあなたのテストフレームワークは同様の概念を持っています。その方法では、SQLを使用してデータベースにレコードを挿入できます。

本番データベースの代わりにテストデータベースを使用するコードを記述するのが難しい場合、アプリケーションのテストの弱点のように思えます。テストには、置換を可能にする依存性注入のようなものを使用する方が良いでしょう。次に、現在のビジネスルールに依存しないテストを作成できます。

これの副次的な利点は、多くの場合、ビジネスオーナー(必ずしも企業階層ではなく、この製品の責任者である企業オーナー)がビジネスルールを直接構成する方が簡単です。この種のテクニカルフレームワークを使用している場合、ビジネスオーナーがユーザーインターフェイス(UI)を使用してオファーを構成できるようにするのは簡単です。ビジネスオーナーはUIで制限を選択し、markLimitedToGender("M")呼び出しを発行します。次に、オファーがデータベースに永続化されると、これが保管されます。しかし、それを使用するためにオファーを保存する必要はありません。そのため、テストでは、データベースに存在しないオファーを作成および構成できます。

上記のシステムでは、ビジネスオーナーはテクニカルグループにリクエストを送信する必要があります。テクニカルグループは適切なSQLを発行し、テストを更新します。または、技術グループがコードとテスト(またはテストの後にコード)を編集する必要があります。それはかなり重いアプローチのようです。できます。しかし、テストするだけでなく、ソフトウェアも、もしそうしなければならないのであれば、壊れにくくなるでしょう。

TL; DR:このようなテストを作成できますが、ソフトウェアを作成する方がよいので、そうする必要はありません。

14
mdfst13