Je sais qu'il est fortement recommandé d'exécuter les tests unitaires dans la séparation du système de fichiers, car si vous touchez le système de fichiers lors de votre test, vous testez également le système de fichiers lui-même. OK, c'est raisonnable.
Ma question est, si je veux tester l'enregistrement de fichier sur le disque, que dois-je faire? Comme avec la base de données, je sépare une interface responsable de l'accès à la base de données, puis en crée une autre pour mes tests. Ou peut-être qu'il y a un autre moyen?Comment tester un fichier sur le disque?
Répondre
Mon approche à cet égard est fortement biaisée sur le livre Growing Object-Oriented Software Guided by Tests (GOOS) que je viens de lire, mais c'est le meilleur que je connaisse aujourd'hui. Spécifiquement:
- Créez une interface pour extraire le système de fichiers de votre code. Mock it où cette classe est nécessaire en tant que collaborateur/dépendance. Cela permet à vos tests unitaires d'être rapides et de réagir rapidement.
- Créez des tests d'intégration qui testent l'implémentation réelle de l'interface. c'est-à-dire vérifier qu'appeler Save() conserve un fichier sur le disque et contient le contenu de l'écriture (utiliser un fichier de référence ou l'analyser pour quelques éléments)
- Créer un test d'acceptation qui teste l'ensemble du système fin. Ici vous pouvez juste vérifier qu'un fichier est créé - l'objectif de ce test est de confirmer si l'implémentation réelle est câblée/branchée correctement.
Mise à jour pour commentateur:
Si vous lisez des données structurées (par exemple, objets Livre) (Dans le cas contraire chaîne de substitution pour IEnumerable)
interface BookRepository
{
IEnumerable<Books> LoadFrom(string filePath);
void SaveTo(string filePath, IEnumerable<Books> books);
}
Maintenant, vous pouvez utiliser constructor- injection pour injecter un faux dans la classe de la clientèle. La classe de client tests unitaires sont donc rapides; ne pas frapper le système de fichiers. Ils vérifient juste que les bonnes méthodes sont appelées sur les dépendances (par exemple Charger/enregistrer)
var testSubject = new Client(new Mock<BookRepository>.Object);
Ensuite, vous devez créer la mise en œuvre réelle de BookRepository qui fonctionne hors d'un fichier (ou un Sql DB tommorrow si vous le voulez). Personne d'autre ne doit savoir. Ecrivez tests d'intégration pour FileBasedBookRepository (qui implémente le rôle ci-dessus) et testez qu'appeler Load avec un fichier de référence donne les bons objets et en appelant Save avec une liste connue, les persiste sur le disque. Par exemple, utilise des fichiers réels Ces tests étant lents, marquez-les avec une étiquette ou placez-les dans une suite distincte.
[TestFixture]
[Category("Integration - Slow")]
public class FileBasedBookRepository
{
[Test]
public void CanLoadBooksFromFileOnDisk() {...}
[Test]
public void CanWriteBooksToFileOnDisk() {...}
}
Enfin, les tests doivent être un/une plus grande acceptation qui exerce la charge et Enregistrer.
Vous pouvez au lieu de transmettre un nom de fichier à votre fonction de sauvegarde, passer un flux, TextWriter ou similaire. Ensuite, lors du test, vous pouvez passer une implémentation basée sur la mémoire et vérifier que les octets corrects sont écrits sans rien écrire sur le disque.
Pour tester les problèmes et les exceptions, vous pouvez jeter un coup d'œil à un cadre de simulation. Cela peut vous aider à générer artificiellement une exception spécifique à un certain moment dans le processus de sauvegarde et à tester que votre code le gère de manière appropriée.
Je me demande si @ chester89 veut aussi des tests pour gérer le 'chemin invalide', 'collision de fichiers',' fichier verrouillé', 'nom de fichier invalide' , 'save interruption', etc. Je suppose que tous ces éléments pourraient aussi être imités. – scunliffe
@scunliffe, oui, j'aimerais tester ces choses aussi. comment puis-je imiter ces comportements? – chester89
@chester: Vous pourriez jeter un oeil à un cadre moqueur. Cela peut vous aider à générer ces exceptions aux moments appropriés. Soyez prudent avant de vous lancer dans le test de chaque condition d'erreur possible et d'avoir 100% de couverture de code à partir des tests. C'est souvent plus cher que cela en vaut la peine. –
Il existe une règle générale d'être prudent lors de l'écriture de tests unitaires qui enregistrent des E/S, car ils ont tendance à être trop lents. Mais il n'y a pas d'interdiction absolue sur les E/S de fichiers dans les tests unitaires.
Dans votre unité, les tests ont un répertoire temporaire configuré et déchiré, et créent des fichiers de test et des répertoires dans ce répertoire temporaire. Oui, vos tests seront plus lents que les tests purement CPU, mais ils seront toujours rapides. JUnit a même un code de support pour aider dans ce scénario: un @Rule
sur un TemporaryFolder
.
Cela dit, le code plus d'écriture de fichiers prend cette forme:
- Ouvrir un flux de sortie vers le fichier. Ce code doit gérer les fichiers manquants ou les problèmes d'autorisations de fichiers. Vous voudrez tester qu'il ouvre le fichier et fait face à ces conditions d'échec.
- Écrire dans le flux de sortie. Cela doit écrire dans le format correct, qui est la partie la plus compliquée nécessitant le plus de tests. Il doit faire face à une erreur d'E/S lors de l'écriture dans le flux de sortie, bien que ces erreurs soient rares dans la pratique.
- Fermez le flux de sortie. Cela doit faire face à une erreur d'E/S lors de la fermeture du flux, bien que ces erreurs soient rares dans la pratique.
Seul le premier traite vraiment du système de fichiers. Le reste utilise juste un flux de sortie.
Ainsi vous pouvez extraire la partie centrale et la dernière partie à sa propre méthode (fonction), qui manipule un flux de sortie donné, plutôt qu'un fichier nommé. Vous pouvez ensuite simuler ce flux de sortie pour tester la méthode unitaire. Ces tests unitaires seront très rapides. La plupart des langages de programmation fournissent déjà une classe de flux de sortie appropriée.
Cela ne laisse que la première partie à être testée à l'unité. Vous n'aurez besoin que de quelques tests, votre suite de tests devrait donc être suffisamment rapide.
Voir aussi http://stackoverflow.com/questions/225073/testing-whats-written-to-a-java-outputstream – Raedwald
Créez une interface pour accéder au système de fichiers. Ensuite, créez son faux, soit en utilisant un cadre moqueur ou à la main. –
merci beaucoup pour les commentaires utiles et les réponses, je pense que je vais rester avec le cadre moqueur – chester89
Test de l'unité ne pas utiliser de systèmes. Ce ne sont pas des tests d'intégration. Le test unitaire ne teste pas la dernière couche, ce qui enregistre le fichier sur le disque. Vous avez besoin de tests d'intégration pour sauvegarder le fichier. Et dans ce cas, il vous suffit de l'enregistrer et de vérifier ensuite qu'il a été créé. C'est un type de test différent, des approches différentes et une histoire différente. La plupart des réponses ci-dessous sont fausses quand elles parlent de tests unitaires mais essayent d'intruder les tests d'intégration. –