72 votes

E / S de fichier de test unitaire

La lecture par le biais de l'unité existante essais des fils ici, sur un Débordement de Pile, je ne pouvais pas en trouver un avec une réponse claire sur la façon de test de l'unité e/S de fichier des opérations. J'ai récemment commencé à regarder dans les tests unitaires, après avoir été conscients des avantages, mais avoir de la difficulté à s'habituer à l'écriture des premiers tests. J'ai mis en place mon projet pour utiliser NUnit et Rhino se moque et même si je comprends le concept derrière eux, je vais avoir un peu de mal à comprendre comment utiliser les Objets Fantaisie.

Plus précisément, j'ai deux questions que j'aimerais avoir des réponses. Tout d'abord, quelle est la bonne façon de test de l'unité e/S de fichier? Deuxièmement, dans mes tentatives pour en apprendre davantage sur les tests unitaires, je suis venu à travers l'injection de dépendance. Après l'obtention de Ninject configurer et de travail, je me demandais si je dois utiliser la DI dans mes tests unitaires, ou tout simplement d'instancier des objets directement.

53voto

Kyralessa Points 76456

Il n'y a pas nécessairement une seule chose à faire lors de l'essai le système de fichiers. En vérité, il ya plusieurs choses que vous pouvez faire, selon les circonstances.

La question que vous devez vous poser est: Que suis-je tester?

  • Que les travaux de système de fichiers? Vous n'avez probablement pas besoin de tester que , sauf si vous utilisez un système d'exploitation qui vous êtes très familier avec. Donc, si vous êtes tout simplement en donnant une commande pour enregistrer des fichiers, par exemple, c'est une perte de temps d'écrire un test pour vous assurer de bien enregistrer.

  • Que les fichiers sont enregistrés à la bonne place? Eh bien, comment savez-vous ce que le droit? Je présume que vous avez le code qui combine un chemin d'accès avec un nom de fichier. C'est un code que vous pouvez tester facilement: Votre participation est de deux chaînes, et votre sortie doit être une chaîne de caractères qui est un fichier valide emplacement construit à l'aide de ces deux chaînes.

  • Que vous obtenez le bon ensemble de fichiers d'un répertoire? Vous aurez probablement à écrire un test pour votre fichier de lecture de la classe qui a vraiment des tests du système de fichiers. Mais vous devez utiliser un répertoire de test avec des fichiers qui ne change pas. Vous devriez également mettre ce test dans un test d'intégration du projet, parce que ce n'est pas un vrai test de l'unité, parce qu'il dépend du système de fichier.

  • Mais, j'ai besoin de faire quelque chose avec les fichiers que je reçois. Pour que le test, vous devez utiliser un faux pour votre fichier de lecture de la classe. Votre faux doit retourner une liste codée en dur de fichiers. Si vous utilisez un vrai fichier-getter et un véritable fichier-processeur, vous ne saurez pas qui provoque un échec de test. Si votre fichier de processeur de classe, dans les essais, doivent faire usage d'un faux fichier de lecture de la classe. Votre fichier de processeur de classe devrait prendre le fichier de lecture de l'interface. Dans le code réel, vous passerez dans le fichier real-getter. Dans le code de test, vous allez passer un faux fichier-getter qui retourne une liste statique.

Les principes fondamentaux sont les suivants:

  • L'utilisation d'un faux système de fichiers, caché derrière une interface, lorsque vous n'êtes pas tester le système de fichiers lui-même.
  • Si vous avez besoin de test réel des opérations de fichier, puis
    • marquer l'essai, comme un test d'intégration, pas un test unitaire.
    • ont désigné un répertoire de test, un ensemble de fichiers, etc. qui sera toujours là dans un état inchangé, de sorte que votre fichier orientée vers les tests d'intégration peut passer de manière cohérente.

38voto

Vadim Points 9146

Découvrez le Tutoriel pour TDD à l'aide de Rhino se moque et SystemWrapper.

SystemWrapper enveloppements beaucoup de Système.IO les classes, y compris Fichier, FileInfo, Annuaire, DirectoryInfo, ... . Vous pouvez voir la liste complète.

Dans ce tutoriel je vous montre comment faire des tests avec MbUnit mais c'est exactement la même pour NUnit.

Votre test va ressembler à quelque chose comme ceci:

[Test]
public void When_try_to_create_directory_that_already_exists_return_false()
{
    var directoryInfoStub = MockRepository.GenerateStub<IDirectoryInfoWrap>();
    directoryInfoStub.Stub(x => x.Exists).Return(true);
    Assert.AreEqual(false, new DirectoryInfoSample().TryToCreateDirectory(directoryInfoStub));

    directoryInfoStub.AssertWasNotCalled(x => x.Create());
}

13voto

Mark Simpson Points 10789

T1:

Vous avez trois options ici.

Option 1: Vivre avec elle.

(pas d'exemple :P)

Option 2: Créer un léger abstraction si nécessaire.

Au lieu de faire de l'e/S de fichier (Fichier.ReadAllBytes ou quoi que ce soit) dans la méthode en cours de test, vous pouvez le modifier de sorte que l'ei est fait à l'extérieur et un flux de données est transmis à la place.

public class MyClassThatOpensFiles
{
    public bool IsDataValid(string filename)
    {
        var filebytes = File.ReadAllBytes(filename);
        DoSomethingWithFile(fileBytes);
    }
}

allait devenir

// File IO is done outside prior to this call, so in the level 
// above the caller would open a file and pass in the stream
public class MyClassThatNoLongerOpensFiles
{
    public bool IsDataValid(Stream stream) // or byte[]
    {
        DoSomethingWithStreamInstead(stream); // can be a memorystream in tests
    }
}

Cette approche est un compromis. Tout d'abord, oui, il est plus vérifiable. Cependant, il négocie la testabilité pour un léger supplément de complexité. Ce qui peut frapper de la maintenabilité et de la quantité de code à écrire, de plus, vous pouvez simplement déplacer vos tests de problème au niveau.

Cependant, dans mon expérience, c'est une belle approche équilibrée comme vous pouvez le généraliser et de rendre testable l'important logique sans vous engager à un entièrement enveloppé de système de fichiers. I. e. vous pouvez généraliser les bits qui compte vraiment pour vous, tout en laissant le reste comme c'est.

Option 3: Enroulez le système de fichiers entier

En prenant un peu plus loin, tourner en dérision le système de fichiers peut être une approche valable; il dépend de la façon dont beaucoup de ballonnements que vous êtes prêt à vivre avec.

J'ai emprunté cette voie avant, j'avais un enroulé du système de fichiers de la mise en œuvre, mais à la fin j'ai juste supprimé. Il y avait des différences subtiles dans l'API, j'ai eu à injecter partout et finalement, c'est mal pour le peu de gain que de nombreuses classes de l'aide ce n'était pas très important pour moi. Si j'avais été en utilisant un conteneur IoC ou écrire quelque chose qui était critique, et les tests nécessaires pour être rapide je pourrais avoir coincé avec elle, si. Comme avec toutes ces options, votre kilométrage peut varier.

Comme pour votre conteneur IoC question:

Injecter votre test en double manuellement. Si vous avez à faire beaucoup de travail répétitif, il suffit d'utiliser le programme d'installation/de l'usine de méthodes dans vos tests. À l'aide d'un conteneur IoC pour le test serait exagéré à l'extrême! Peut-être que je ne suis pas la compréhension de votre deuxième question, cependant.

1voto

Grant Palin Points 3459

Actuellement, je consomme un objet IFileSystem via une injection de dépendance. Pour le code de production, une classe wrapper implémente l'interface en encapsulant les fonctions IO spécifiques dont j'ai besoin. Lors du test, je peux créer une implémentation null ou stub et la fournir à la classe sous test. La classe testée n’est pas la plus sage.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X