私は、チームで実装しているユニットテストに関して、ますます厄介な問題に取り組んでいます。うまく設計されていないユニットコードをレガシーコードに追加しようとしていますが、実際にテストを追加するのに苦労することはありませんが、テストの結果に苦労し始めています。
問題の例として、実行の一部として5つの他のメソッドを呼び出すメソッドがあるとしましょう。このメソッドのテストは、これらの5つのメソッドのいずれかが呼び出された結果として動作が発生することを確認することです。そのため、単体テストは1つの理由と1つの理由でのみ失敗するはずなので、これらの他の4つのメソッドを呼び出して発生する潜在的な問題を排除し、それらをモックアウトする必要があります。すばらしいです!単体テストが実行され、モックされたメソッドは無視され(その動作は他の単体テストの一部として確認できます)、検証が機能します。
しかし、新しい問題があります-単体テストには、今後、他の4つのメソッドのいずれかに対する動作とシグネチャの変更、または「親メソッド」に追加する必要のある新しいメソッドの確認方法に関する詳細な知識があります。失敗の可能性を回避するために、単体テストを変更する必要があります。
当然のことながら、より多くのメソッドがより少ない動作を達成するようにするだけで、問題を多少軽減できますが、おそらくよりエレガントなソリューションが利用できることを望んでいました。
問題をキャプチャする単体テストの例を次に示します。
簡単なメモとして、「MergeTests」は単体テストクラスであり、テストしているクラスから継承し、必要に応じて動作をオーバーライドします。これは、外部クラス/依存関係への呼び出しをオーバーライドできるようにするためにテストで使用する「パターン」です。
[TestMethod]
public void VerifyMergeStopsSpinner()
{
var mockViewModel = new Mock<MergeTests> { CallBase = true };
var mockMergeInfo = new MergeInfo(Mock.Of<IClaim>(), Mock.Of<IClaim>(), It.IsAny<bool>());
mockViewModel.Setup(m => m.ClaimView).Returns(Mock.Of<IClaimView>);
mockViewModel.Setup(
m =>
m.TryMergeClaims(It.IsAny<Func<bool>>(), It.IsAny<IClaim>(), It.IsAny<IClaim>(), It.IsAny<bool>(),
It.IsAny<bool>()));
mockViewModel.Setup(m => m.GetSourceClaimAndTargetClaimByMergeState(It.IsAny<MergeState>())).Returns(mockMergeInfo);
mockViewModel.Setup(m => m.SwitchToOverviewTab());
mockViewModel.Setup(m => m.IncrementSaveRequiredNotification());
mockViewModel.Setup(m => m.OnValidateAndSaveAll(It.IsAny<object>()));
mockViewModel.Setup(m => m.ProcessPendingActions(It.IsAny<string>()));
mockViewModel.Object.OnMerge(It.IsAny<MergeState>());
mockViewModel.Verify(mvm => mvm.StopSpinner(), Times.Once());
}
残りの人はどのようにこれに対処しましたか、またはそれを処理する優れた「シンプルな」方法はありませんか?
更新-皆さんのフィードバックに感謝します。残念ながら、実際に驚くことではありません。テスト対象のコードが貧弱であれば、単体テストで従うことのできる優れたソリューション、パターン、または実践はないようです。この単純な真実を最もよく捉えた答えをマークしました。