Je me bats avec un problème de plus en plus ennuyeux concernant nos tests unitaires que nous mettons en œuvre dans mon équipe. Nous essayons d'ajouter des tests unitaires dans du code hérité qui n'était pas bien conçu et même si nous n'avons eu aucune difficulté avec l'ajout réel des tests, nous commençons à avoir du mal avec la façon dont les tests se déroulent.
Comme exemple du problème, supposons que vous ayez une méthode qui appelle 5 autres méthodes dans le cadre de son exécution. Un test pour cette méthode pourrait être de confirmer qu'un comportement se produit à la suite de l'appel de l'une de ces 5 autres méthodes. Donc, comme un test unitaire doit échouer pour une raison et une seule raison, vous voulez éliminer les problèmes potentiels causés par l'appel de ces 4 autres méthodes et les simuler. Génial! Le test unitaire s'exécute, les méthodes simulées sont ignorées (et leur comportement peut être confirmé dans le cadre d'autres tests unitaires), et la vérification fonctionne.
Mais il y a un nouveau problème - le test unitaire a une connaissance intime de la façon dont vous avez confirmé que le comportement et toute modification de signature à l'une de ces 4 autres méthodes à l'avenir, ou toute nouvelle méthode qui doit être ajoutée à la `` méthode parent '', sera oblige à modifier le test unitaire pour éviter d'éventuelles pannes.
Naturellement, le problème pourrait être quelque peu atténué en faisant simplement en sorte que plus de méthodes accomplissent moins de comportements, mais j'espérais qu'il y avait peut-être une solution plus élégante disponible.
Voici un exemple de test unitaire qui capture le problème.
Comme note rapide, «MergeTests» est une classe de tests unitaires qui hérite de la classe que nous testons et remplace le comportement au besoin. Il s'agit d'un «modèle» que nous utilisons dans nos tests pour nous permettre de remplacer les appels à des classes / dépendances externes.
[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());
}
Comment le reste d'entre vous avez-vous géré cela ou n'y a-t-il pas une excellente manière «simple» de le gérer?
Mise à jour - J'apprécie les commentaires de tout le monde. Malheureusement, et ce n'est pas vraiment une surprise, il ne semble pas y avoir une excellente solution, un modèle ou une pratique à suivre dans les tests unitaires si le code testé est médiocre. J'ai marqué la réponse qui captait le mieux cette simple vérité.