2017-07-28 1 views
0

Je veux tester du code qui inclut des instructions d'impression dont je ne peux malheureusement pas me débarrasser. Mon approche consistait à capturer stdout pendant les tests et à effectuer des assertions sur les sorties capturées. Je voulais extraire ce code de redirection pour le rendre utilisable par de nombreux cas de test. Par exemple, une fonction très simple comme celui-ciComment extraire la redirection stdout dans le code unittest pour le rendre réutilisable en toute sécurité par d'autres cas de test?

# something.py 

def function(): 
    print("something") 
    return 42 

serait testé comme celui-ci

import io 
import sys 
import unittest 
import something 

# test_something.py 

class RedirectTestCase(unittest.TestCase): 

    def setUp(self): 
     self.original_stdout = sys.stdout 
     self.temporary_stdout = io.StringIO() 
     sys.stdout = self.temporary_stdout 

    def tearDown(self): 
     sys.stdout = self.original_stdout 

    def assertOutputEqual(self, expected_output): 
     self.temporary_stdout.seek(0) 
     captured_output = self.temporary_stdout.read().strip() 
     self.assertEqual(expected_output, captured_output) 


class TestFunction(RedirectTestCase): 

    def setUp(self): 
     super().setUp() 

    def tearDown(self): 
     super().tearDown() 

    def test_output(self): 
     something.function() 
     self.assertOutputEqual("something") 

    def test_return(self): 
     self.assertEqual(42, something.function()) 


if __name__ == "__main__": 
    unittest.main() 

J'extrait le code de redirection de stdout dans une classe de base, mais je n'aime pas appeler les classes de base setUp et tearDown méthodes dans chaque implémentation de cas de test. Y a-t-il une meilleure façon de rendre cette approche accessible à plusieurs cas de test? Surtout, est-il possible d'appeler automatiquement les classes de base setUp et tearDown pour rendre les tests plus propres et plus sûrs? Toutes les autres suggestions pour améliorer cette approche de test sont très appréciées!

Répondre

0

J'ai trouvé un blog post par Ned Betchelder couvrant un problème similaire en utilisant une classe de mixin. J'ai utilisé cette approche pour restructurer les tests. Il divise le code en éléments indépendants et les appels super() sont évités dans les cas de test réels.

class BaseTestCase(unittest.TestCase): 
    """Base test case.""" 

    def setUp(self): 
     super().setUp() 
     # do basic setup stuff here ... 

    def tearDown(self): 
     # do basic teardown stuff here ... 
     super().tearDown() 

    def assertOutputEqual(self, expected_output): 
     self.temporary_stdout.seek(0) 
     captured_output = self.temporary_stdout.read().strip() 
     self.assertEqual(expected_output, captured_output) 


class RedirectMixin(object): 
    """Mixin class for redirecting stdout on setup and teardown.""" 

    def setUp(self): 
     super().setUp() 
     self.original_stdout = sys.stdout 
     self.temporary_stdout = io.StringIO() 
     sys.stdout = self.temporary_stdout 

    def tearDown(self): 
     sys.stdout = self.original_stdout 
     super().tearDown() 


class TestFunction(RedirectMixin, BaseTestCase): 
    """Actual test case using stdout redirection.""" 

    def test_output(self): 
     something.function() 
     self.assertOutputEqual("something") 

    def test_return(self): 
     self.assertEqual(42, something.function())