参照を介してオブジェクトが更新されることを期待しているメソッドを単体テストするにはどうすればよいですか?
-
07-07-2019 - |
質問
渡される参照型の一部のプロパティを変更するメソッドの単体テストに問題があります。
例として、Policyというクラスがあるとします。
Policy policy = new Policy();
policy.Status = Active;
このポリシーをポリシーマネージャーに渡して、ポリシーを無効にします。
policyManager.InactivatePolicy(policy);
ポリシーの非アクティブ化メソッドは次のことを行います。
public void InactivatePolicy(Policy policy)
{
policy.Status = Inactive;
UpdatePolicy(policy); //saves the updated policy details via nhibernate
}
私が問題を抱えているのは、このDoSomethingメソッドの単体テストです。 (この例で行うことは役に立たないという事実を無視してください)
public void DoSomething(Policy policy)
{
Policy policy = new Policy();
policy.Status = Active;
policyManager.InactivatePolicy(policy);
}
Policy Managerをモックアウトしているため、ステータスが非アクティブに設定されません その結果、DoSomethingが呼び出された後、 ポリシーは非アクティブです。ポリシーはまだアクティブであるため、テストに失敗します。
[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
MyClass mc = new MyClass(policyManagerMock.Object);
Policy policy = new Policy();
policy.Status = Active;
mc.DoSomething(policy);
Assert.That(policy.Status, Is.EqualTo(Inactive)); //this fails
}
だから私はコードが実際に機能する状況にいますが、単体テストで隔離されているときだけではありません。
この問題を回避できる唯一の方法は、ポリシーマネージャーのInactivatePolicyメソッドが変更された 期待される戻り値をモックアップできるようにするポリシー。
public Policy InactivatePolicy(Policy policy)
{
policy.Status = Inactive;
UpdatePolicy(policy); //saves the updated policy details via nhibernate
return policy;
}
[Test]
public void TheStatusShouldBeInactiveWhenWeDoSomething()
{
Mock<IPolicyManager> policyManagerMock = new Mock<PolicyManager>();
MyClass mc = new MyClass(policyManagerMock.Object);
Policy expectedInactivePolicy = new Policy();
expectedInactivePolicy.Status = Inactive;
Policy policy = new Policy();
policy.Status = Active;
policyManagerMock
.Setup(p => p.InactivatePolicy(policy))
.Returns(expectedInactivePolicy);
mc.DoSomething(policy);
Assert.That(policy.Status, Is.EqualTo(Inactive)); //this now succeeds
}
通常、何かを単体テストするのに苦労しているとき、それは間違ったことをしていることを示しています。
これを行うより良い方法があるかどうか誰もが知っていますか?メソッドに渡された参照値を介して更新されることを最初に意図されていた値を返すことを本質的に強制されていますか?
おそらく、ポリシーマネージャーにInactivatePolicyメソッドを含めるべきではなく、ポリシーオブジェクト自体にあり、データベースの更新を後で呼び出す必要があるという私の問題ですか?
解決
PolicyManagerをモックアウトするのではなく、DoSomethingメソッドの機能をテストしたいので、UpdatePolicyメソッドをモックアウトする必要があります。
また、おそらくツリーの上位でテストしすぎています。
InactivatePolicy()メソッドを単独でテストし、機能が機能していることのみをテストしてから、DoSomething()メソッドをもう一度Isolationでテストする必要があります。
ここには2つの個別のコードユニットがあり、各ユニットを具体的にテストするユニットテストが必要です。
他のヒント
ランブリング
あまり従わない。
NHibernateを介して true
に設定されるという事実をテストしていない場合(つまり、それが機能すると仮定するつもりなら)、あなたは何をテストしますか?実稼働コードではそうであると仮定しているのに、なぜ値が設定されるのをテストするのが面倒なのでしょうか?たとえそれをtrueに設定するシステムを簡単にモックアップしたとしても、実稼働コードと同じではないため、ポイントはわかりません。
せいぜい、「あざける」データストアを持つことを検討します。 nHibernateではなく、それは何もしません。この場合、「nHibernateRepo」ではなく「MockRepo」を使用して、 UpdatePolicy
クラスに実装されます。
このようにして、リポジトリを適切に設定すると、設定されていることがわかります。
nHibernateコードにバグがある可能性があり、事実上、チェックしているのはブール値の設定だけなので、そのポイントは疑問に思うでしょう。
概要
このテストを実行できるテスト開発データベースが存在しないのはなぜですか?
実際には、元のオブジェクトをテストするのではなく、モックオブジェクトとそのポリシーオブジェクトのアクティブ状態への影響をテストしており、実際のシナリオでテストに合格した場合でも、PolicyManagerは異なる動作をしてDoSomethingを引き起こすため、テストは間違っていると思います失敗する。 たぶん、単体テストでPolicyManagerとそのUpdateInactiveメソッドをテストして、 DoSomethingを実際のPolicyManagerとともにテストする整合性テスト。