test: split SubprocessTestCase.run into setUp/tearDown
authorPeter Wu <peter@lekensteyn.nl>
Thu, 3 Jan 2019 18:07:40 +0000 (19:07 +0100)
committerAnders Broman <a.broman58@gmail.com>
Fri, 4 Jan 2019 04:58:25 +0000 (04:58 +0000)
The run method is not invoked when running in debug mode (for example,
with `pytest --pdb`) and would result in spurious errors due to "log_fd"
being None. Split the method to resolve this incompatibility.

Note that with `pytest --pdb`, the tearDown method is not called when
exceptions occur, see https://docs.pytest.org/en/latest/unittest.html

Change-Id: I4b66c03d5b050b53311ec64021fe17dc91bb48dd
Reviewed-on: https://code.wireshark.org/review/31339
Petri-Dish: Peter Wu <peter@lekensteyn.nl>
Tested-by: Petri Dish Buildbot
Reviewed-by: Anders Broman <a.broman58@gmail.com>
test/subprocesstest.py

index 2510ce8992d21dfb1695f9edc0bdab6b0ac5f3ff..fafd77314469f5f358650933b4f2729afebd3df9 100644 (file)
@@ -130,25 +130,10 @@ class SubprocessTestCase(unittest.TestCase):
             except:
                 pass
 
-    def _error_count(self, result):
-        if not result:
-            return 0
-        if hasattr(result, 'failures'):
-            # Python standard unittest runner
-            return len(result.failures) + len(result.errors)
-        if hasattr(result, '_excinfo'):
-            # pytest test runner
-            return len(result._excinfo or [])
-        self.fail("Unexpected test result %r" % result)
-
-    def run(self, result=None):
-        # Subclass run() so that we can do the following:
-        # - Open our log file and add it to the cleanup list.
-        # - Check our result before and after the run so that we can tell
-        #   if the current test was successful.
-
-        # Probably not needed, but shouldn't hurt.
-        self.kill_processes()
+    def setUp(self):
+        """
+        Set up a single test. Opens a log file and add it to the cleanup list.
+        """
         self.processes = []
         self.log_fname = self.filename_from_id('log')
         # Our command line utilities generate UTF-8. The log file endcoding
@@ -157,27 +142,35 @@ class SubprocessTestCase(unittest.TestCase):
         # to handle line endings in the future.
         self.log_fd = io.open(self.log_fname, 'w', encoding='UTF-8', newline='\n')
         self.cleanup_files.append(self.log_fname)
-        pre_run_problem_count = self._error_count(result)
-        try:
-            super().run(result=result)
-        except KeyboardInterrupt:
-            # XXX This doesn't seem to work on Windows, which is where we need it the most.
-            self.kill_processes()
-
-        # Tear down our test. We don't do this in tearDown() because Python 3
-        # updates "result" after calling tearDown().
+
+    def _last_test_failed(self):
+        """Check for non-skipped tests that resulted in errors."""
+        # The test outcome is not available via the public unittest API, so
+        # check a private property, "_outcome", set by unittest.TestCase.run.
+        # It remains None when running in debug mode (`pytest --pdb`).
+        # The property is available since Python 3.4 until at least Python 3.7.
+        if self._outcome:
+            for test_case, exc_info in self._outcome.errors:
+                if exc_info:
+                    return True
+        # No errors occurred or running in debug mode.
+        return False
+
+    def tearDown(self):
+        """
+        Tears down a single test. Kills stray processes and closes the log file.
+        On errors, display the log contents. On success, remove temporary files.
+        """
         self.kill_processes()
         self.log_fd.close()
-        if result:
-            post_run_problem_count = self._error_count(result)
-            if pre_run_problem_count != post_run_problem_count:
-                self.dump_files.append(self.log_fname)
-                # Leave some evidence behind.
-                self.cleanup_files = []
-                print('\nProcess output for {}:'.format(self.id()))
-                with io.open(self.log_fname, 'r', encoding='UTF-8', errors='backslashreplace') as log_fd:
-                    for line in log_fd:
-                        sys.stdout.write(line)
+        if self._last_test_failed():
+            self.dump_files.append(self.log_fname)
+            # Leave some evidence behind.
+            self.cleanup_files = []
+            print('\nProcess output for {}:'.format(self.id()))
+            with io.open(self.log_fname, 'r', encoding='UTF-8', errors='backslashreplace') as log_fd:
+                for line in log_fd:
+                    sys.stdout.write(line)
         for filename in self.cleanup_files:
             try:
                 os.unlink(filename)