2017-07-28 1 views
0

Ich möchte Code testen, der einige Druckanweisungen enthält, die ich leider nicht loswerden kann. Mein Ansatz bestand darin, während der Tests Stdout zu erfassen und Assertionen auf den erfassten Ausgaben durchzuführen. Ich wollte diesen Umleitungscode extrahieren, um ihn für viele Testfälle nutzbar zu machen. Zum Beispiel kann eine sehr einfache Funktion wie dieseWie extrahiert man die stdout-Umleitung im Unittest-Code, um sie durch andere Testfälle wieder verwendbar zu machen?

# something.py 

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

würde wie diese

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() 

getestet werden ich die stdout Umleitung Code in einer Basisklasse extrahiert, aber ich weiß nicht, wie die Basisklassen setUp aufrufen und tearDown Methoden in jeder Testfallimplementierung. Gibt es eine bessere Möglichkeit, diesen Ansatz mehreren Testfällen zugänglich zu machen? Insbesondere ist es möglich, die Basisklassen setUp und tearDown automatisch aufzurufen, um die Tests sauberer und sicherer zu machen? Alle anderen Vorschläge zur Verbesserung dieses Testansatzes werden sehr geschätzt!

Antwort

0

Ich fand eine blog post von Ned Betchelder für ein ähnliches Problem mit einer Mixin-Klasse. Ich benutzte diesen Ansatz, um die Tests neu zu strukturieren. Es teilt den Code in unabhängige Teile auf und die Aufrufe super() werden in den tatsächlichen Testfällen vermieden.

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()) 
Verwandte Themen