2010-02-12 10 views
6

Lorsque vous testez une base de code, quels sont les signes révélateurs dont j'ai besoin pour utiliser des objets fictifs?Unité testant les méthodes void/signes de contes d'objets moqueurs

Serait-ce aussi simple que de voir beaucoup d'appels à d'autres objets dans le code?

De même, comment est-ce que je pourrais tester des méthodes qui ne renvoient pas de valeurs? Donc, si une méthode renvoie void mais imprime dans un fichier, est-ce que je vérifie simplement le contenu du fichier? Mocking est pour les dépendances externes, donc c'est littéralement tout, non? Système de fichiers, db, réseau, etc ...

+0

Pour votre dernier point, vérifiez: http://martinfowler.com/articles/mocksArentStubs.html juste pour vous assurer que vous êtes conscient des différences. – Finglas

+0

Voici une bonne lecture répondant à certaines de ces questions: http://xunitpatterns.com/TestStrategy.html –

Répondre

2

Si quoi que ce soit, j'utilise probablement trop de mocks.

Chaque fois qu'une classe appelle une autre, en général je moque cet appel, et je vérifie que l'appel a été fait avec les paramètres corrects. Sinon où, je vais avoir un test unitaire qui vérifie le code concret de l'objet mocké se comporte correctement.

Exemple:

[Test] 
public void FooMoo_callsBarBaz_whenXisGreaterThan5() 
{ 
    int TEST_DATA = 6; 
    var bar = new Mock<Bar>(); 
    bar.Setup(x => x.Baz(It.Is<int>(i == TEST_DATA))) 
     .Verifiable(); 

    var foo = new Foo(bar.Object); 

    foo.moo(TEST_DATA); 

    bar.Verify(); 
} 

... 
[Test] 
public void BarBaz_doesSomething_whenCalled() 
{ 
    // another test 
} 

La chose pour moi, si j'essaie de tester beaucoup de classes comme un grand glob, alors il est généralement tonnes de code de configuration. Non seulement cela est assez déroutant à lire que vous essayez de comprendre toutes les dépendances, mais c'est très fragile quand des changements doivent être faits. Je préfère de loin les petits tests succincts. Plus facile à écrire, plus facile à maintenir, plus facile à comprendre l'intention du test.

+4

Vous finissez par attacher le test aux détails de l'implémentation interne par des simulacres qui signifient qu'ils ont tendance à se casser plus souvent. Avec les tests basés sur l'état, vous ne vous souciez que d'une sortie. Les mocks sont généralement plus malpropres à installer, mais ils ont certainement leur place dans les tests unitaires. – Finglas

-1

Les tests unitaires sont uniquement pour un morceau de code qui fonctionne de manière autonome en lui-même. Cela signifie qu'il ne dépend pas d'autres objets pour faire son travail. Vous devriez utiliser des simulacres si vous faites de la programmation pilotée par les tests ou de la programmation Test-First. Vous créez un simulacre (ou stub comme j'aime l'appeler) de la fonction que vous allez créer et définissez certaines conditions pour que le test passe. A l'origine, la fonction renvoie false et le test échoue, ce qui est attendu ... alors vous écrivez le code pour faire le vrai travail jusqu'à ce qu'il passe. Mais ce que je pense que vous faites allusion à est des tests d'intégration, pas des tests unitaires. Dans ce cas, vous devez utiliser des mock si vous attendez que d'autres programmeurs terminent leur travail et que vous n'ayez pas accès aux fonctions ou aux objets qu'ils sont en train de créer. Si vous connaissez l'interface, qui, je l'espère, vous raillez autrement est inutile et une perte de temps, alors vous pouvez créer une version simplifiée de ce que vous espérez obtenir dans le futur.

En bref, les mocks sont mieux utilisés lorsque vous attendez d'autres personnes et que vous avez besoin de quelque chose pour terminer votre travail.

Vous devriez toujours retourner une valeur si possible. Parfois, vous rencontrez des problèmes lorsque vous renvoyez déjà quelque chose, mais en C et C++, vous pouvez avoir des paramètres de sortie, puis utiliser la valeur de retour pour la vérification des erreurs.

+0

-1 - Ceci est basé sur un malentendu de mocks et de talons. Tandis que vous remplissez certainement la fonctionnalité en faisant TDD, ce n'est pas ce que les objets de simulation sont pour. Vous ne vous moquez pas de l'objet testé, vous vous moquez de ses dépendances. – TrueWill

+0

Ouais, je suppose qu'il y a une différence entre les talons et les faux-semblants. Je pense que vous avez mal compris ce que j'ai dit. Dans le premier paragraphe, je décrivais quels tests unitaires étaient et comment vous pourriez utiliser un objet que vous avez créé et qui simule un objet réel auquel vous n'avez actuellement pas accès ou auquel vous n'avez pas accès. Dans le deuxième paragraphe j'ai commencé à décrire que les simulacres sont pour les tests d'intégration ... mais j'avais tort. Les tests d'intégration sont effectués après les tests unitaires et se font avec des objets réels, et non des simulacres. Quoi qu'il en soit, les simulacres sont mieux utilisés lorsque vous voulez faire des tests unitaires avant de les intégrer. –

0

Mock/stubs/fakes/test double/etc. sont bien dans les tests unitaires, et permettent de tester la classe/système sous test en isolation. Les tests d'intégration peuvent ne pas utiliser de faux-semblant; ils frappent réellement la base de données ou toute autre dépendance externe.

Vous utilisez un simulacre ou un bout quand vous en avez besoin. En général, cela est dû au fait que la classe que vous essayez de tester dépend d'une interface. Pour TDD, vous voulez programmer des interfaces, pas des implémentations, et utiliser l'injection de dépendance (en général).

Un cas très simple:

public class ClassToTest 
{ 
    public ClassToTest(IDependency dependency) 
    { 
     _dependency = dependency; 
    } 

    public bool MethodToTest() 
    { 
     return _dependency.DoSomething(); 
    } 
} 

IDependency est une interface, peut-être un avec des appels coûteux (accès à la base, les appels de service Web, etc.). Une méthode d'essai peut contenir un code similaire à:

// Arrange 

var mock = new Mock<IDependency>(); 

mock.Setup(x => x.DoSomething()).Returns(true); 

var systemUnderTest = new ClassToTest(mock.Object); 

// Act 

bool result = systemUnderTest.MethodToTest(); 

// Assert 

Assert.That(result, Is.True); 

Notez que je fais des tests d'état (comme suggéré @Finglas), et je ne faire valoir contre le système en cours de test (l'instance de la classe I » m test). Je peux vérifier les valeurs de propriété (état) ou la valeur de retour d'une méthode, comme le montre ce cas. Je recommande de lire The Art of Unit Testing, surtout si vous utilisez .NET.

Questions connexes