From 12c0b33cf1b1fcba2b48474c1a149f6b1581fa7f Mon Sep 17 00:00:00 2001 From: ejochman <34144949+ejochman@users.noreply.github.com> Date: Sat, 4 Jan 2020 10:24:07 -0800 Subject: [PATCH] Buffer unittests to avoid output to build log (#1070) Requires use of a context manager within each test method for stdout/stderr patches, rather than the @patch.object decorator. Otherwise, the test runner hijacks the patched object before the method under test can use it. Note: The `--buffer` switch in the unittest module will suppress all output during the test, unless the test fails. However, with this implementation, anything that would have been printed to the streams within the context manager will not be reflected in the test runner's output, should the test fail. See more in jay0lee/GAM#1068 --- .travis.yml | 4 +-- src/controlflow_test.py | 24 +++++++-------- src/display_test.py | 36 +++++++++++----------- src/gapi/__init___test.py | 64 +++++++++++++++++++-------------------- 4 files changed, 62 insertions(+), 66 deletions(-) diff --git a/.travis.yml b/.travis.yml index cf1c9276..f1f51477 100644 --- a/.travis.yml +++ b/.travis.yml @@ -196,8 +196,8 @@ install: - source src/travis/$TRAVIS_OS_NAME-$PLATFORM-install.sh script: -# Discover and run all Python unit tests -- $python -m unittest discover -s ./ -p "*_test.py" +# Discover and run all Python unit tests. Buffer output so that it's not sent to the build log. +- $python -m unittest discover --start-directory ./ --pattern "*_test.py" --buffer - $gam version extended - $gam version | grep travis # travis should be part of the path (not /tmp or such) # determine which Python version GAM is built with and ensure it's at least build version from above. diff --git a/src/controlflow_test.py b/src/controlflow_test.py index 1b19afe9..e9ce0e66 100644 --- a/src/controlflow_test.py +++ b/src/controlflow_test.py @@ -86,23 +86,21 @@ class ControlFlowTest(unittest.TestCase): # Prevent the system from actually sleeping and thus slowing down the test. @patch.object(controlflow.time, 'sleep') - @patch.object(controlflow.sys.stderr, 'write') - def test_wait_on_failure_prints_errors(self, mock_stderr_write, - unused_mock_sleep): + def test_wait_on_failure_prints_errors(self, unused_mock_sleep): message = 'An error message to display' - controlflow.wait_on_failure(1, 5, message, error_print_threshold=0) + with patch.object(controlflow.sys.stderr, 'write') as mock_stderr_write: + controlflow.wait_on_failure(1, 5, message, error_print_threshold=0) self.assertIn(message, mock_stderr_write.call_args[0][0]) @patch.object(controlflow.time, 'sleep') - @patch.object(controlflow.sys.stderr, 'write') - def test_wait_on_failure_only_prints_after_threshold(self, mock_stderr_write, - unused_mock_sleep): + def test_wait_on_failure_only_prints_after_threshold(self, unused_mock_sleep): total_attempts = 5 threshold = 3 - for attempt in range(1, total_attempts + 1): - controlflow.wait_on_failure( - attempt, - total_attempts, - 'Attempt #%s' % attempt, - error_print_threshold=threshold) + with patch.object(controlflow.sys.stderr, 'write') as mock_stderr_write: + for attempt in range(1, total_attempts + 1): + controlflow.wait_on_failure( + attempt, + total_attempts, + 'Attempt #%s' % attempt, + error_print_threshold=threshold) self.assertEqual(total_attempts - threshold, mock_stderr_write.call_count) diff --git a/src/display_test.py b/src/display_test.py index d2e38d0c..4dde2f70 100644 --- a/src/display_test.py +++ b/src/display_test.py @@ -10,50 +10,50 @@ from var import WARNING_PREFIX class DisplayTest(unittest.TestCase): - @patch.object(display.sys.stderr, 'write') - def test_print_error_prints_to_stderr(self, mock_write): + def test_print_error_prints_to_stderr(self): message = 'test error' - display.print_error(message) + with patch.object(display.sys.stderr, 'write') as mock_write: + display.print_error(message) printed_message = mock_write.call_args[0][0] self.assertIn(message, printed_message) - @patch.object(display.sys.stderr, 'write') - def test_print_error_prints_error_prefix(self, mock_write): + def test_print_error_prints_error_prefix(self): message = 'test error' - display.print_error(message) + with patch.object(display.sys.stderr, 'write') as mock_write: + display.print_error(message) printed_message = mock_write.call_args[0][0] self.assertLess( printed_message.find(ERROR_PREFIX), printed_message.find(message), 'The error prefix does not appear before the error message') - @patch.object(display.sys.stderr, 'write') - def test_print_error_ends_message_with_newline(self, mock_write): + def test_print_error_ends_message_with_newline(self): message = 'test error' - display.print_error(message) + with patch.object(display.sys.stderr, 'write') as mock_write: + display.print_error(message) printed_message = mock_write.call_args[0][0] self.assertRegex(printed_message, '\n$', 'The error message does not end in a newline.') - @patch.object(display.sys.stderr, 'write') - def test_print_warning_prints_to_stderr(self, mock_write): + def test_print_warning_prints_to_stderr(self): message = 'test warning' - display.print_warning(message) + with patch.object(display.sys.stderr, 'write') as mock_write: + display.print_error(message) printed_message = mock_write.call_args[0][0] self.assertIn(message, printed_message) - @patch.object(display.sys.stderr, 'write') - def test_print_warning_prints_error_prefix(self, mock_write): + def test_print_warning_prints_error_prefix(self): message = 'test warning' - display.print_error(message) + with patch.object(display.sys.stderr, 'write') as mock_write: + display.print_error(message) printed_message = mock_write.call_args[0][0] self.assertLess( printed_message.find(WARNING_PREFIX), printed_message.find(message), 'The warning prefix does not appear before the error message') - @patch.object(display.sys.stderr, 'write') - def test_print_warning_ends_message_with_newline(self, mock_write): + def test_print_warning_ends_message_with_newline(self): message = 'test warning' - display.print_error(message) + with patch.object(display.sys.stderr, 'write') as mock_write: + display.print_error(message) printed_message = mock_write.call_args[0][0] self.assertRegex(printed_message, '\n$', 'The warning message does not end in a newline.') diff --git a/src/gapi/__init___test.py b/src/gapi/__init___test.py index 679fa395..8758446d 100644 --- a/src/gapi/__init___test.py +++ b/src/gapi/__init___test.py @@ -361,25 +361,25 @@ class GapiTest(unittest.TestCase): self.assertIn('pageSize', request_method_kwargs) self.assertEqual(123456, request_method_kwargs['pageSize']) - @patch.object(gapi.sys.stderr, 'write') - def test_get_all_pages_prints_paging_message(self, mock_write): + def test_get_all_pages_prints_paging_message(self): self.mock_method.return_value.execute.side_effect = self.simple_3_page_response paging_message = 'A simple string displayed during paging' - gapi.get_all_pages( - self.mock_service, self.mock_method_name, page_message=paging_message) + with patch.object(gapi.sys.stderr, 'write') as mock_write: + gapi.get_all_pages( + self.mock_service, self.mock_method_name, page_message=paging_message) messages_written = [ call_args[0][0] for call_args in mock_write.call_args_list ] self.assertIn(paging_message, messages_written) - @patch.object(gapi.sys.stderr, 'write') - def test_get_all_pages_prints_paging_message_inline(self, mock_write): + def test_get_all_pages_prints_paging_message_inline(self): self.mock_method.return_value.execute.side_effect = self.simple_3_page_response paging_message = 'A simple string displayed during paging' - gapi.get_all_pages( - self.mock_service, self.mock_method_name, page_message=paging_message) + with patch.object(gapi.sys.stderr, 'write') as mock_write: + gapi.get_all_pages( + self.mock_service, self.mock_method_name, page_message=paging_message) messages_written = [ call_args[0][0] for call_args in mock_write.call_args_list ] @@ -394,13 +394,13 @@ class GapiTest(unittest.TestCase): paging_message_call_positions[0]:paging_message_call_positions[1]] self.assertIn('\r', printed_between_page_messages) - @patch.object(gapi.sys.stderr, 'write') - def test_get_all_pages_ends_paging_message_with_newline(self, mock_write): + def test_get_all_pages_ends_paging_message_with_newline(self): self.mock_method.return_value.execute.side_effect = self.simple_3_page_response paging_message = 'A simple string displayed during paging' - gapi.get_all_pages( - self.mock_service, self.mock_method_name, page_message=paging_message) + with patch.object(gapi.sys.stderr, 'write') as mock_write: + gapi.get_all_pages( + self.mock_service, self.mock_method_name, page_message=paging_message) messages_written = [ call_args[0][0] for call_args in mock_write.call_args_list ] @@ -410,14 +410,13 @@ class GapiTest(unittest.TestCase): messages_written) - messages_written[::-1].index('\r\n') self.assertGreater(last_carriage_return_index, last_page_message_index) - @patch.object(gapi.sys.stderr, 'write') - def test_get_all_pages_prints_attribute_total_items_in_paging_message( - self, mock_write): + def test_get_all_pages_prints_attribute_total_items_in_paging_message(self): self.mock_method.return_value.execute.side_effect = self.simple_3_page_response paging_message = 'Total number of items discovered: %%total_items%%' - gapi.get_all_pages( - self.mock_service, self.mock_method_name, page_message=paging_message) + with patch.object(gapi.sys.stderr, 'write') as mock_write: + gapi.get_all_pages( + self.mock_service, self.mock_method_name, page_message=paging_message) messages_written = [ call_args[0][0] for call_args in mock_write.call_args_list @@ -442,17 +441,17 @@ class GapiTest(unittest.TestCase): for message in messages_written: self.assertNotIn('%%total_items', message) - @patch.object(gapi.sys.stderr, 'write') - def test_get_all_pages_prints_attribute_first_item_in_paging_message( - self, mock_write): + def test_get_all_pages_prints_attribute_first_item_in_paging_message(self): self.mock_method.return_value.execute.side_effect = self.simple_3_page_response paging_message = 'First item in page: %%first_item%%' - gapi.get_all_pages( - self.mock_service, - self.mock_method_name, - page_message=paging_message, - message_attribute='position') + + with patch.object(gapi.sys.stderr, 'write') as mock_write: + gapi.get_all_pages( + self.mock_service, + self.mock_method_name, + page_message=paging_message, + message_attribute='position') messages_written = [ call_args[0][0] for call_args in mock_write.call_args_list @@ -471,17 +470,16 @@ class GapiTest(unittest.TestCase): for message in messages_written: self.assertNotIn('%%first_item', message) - @patch.object(gapi.sys.stderr, 'write') - def test_get_all_pages_prints_attribute_last_item_in_paging_message( - self, mock_write): + def test_get_all_pages_prints_attribute_last_item_in_paging_message(self): self.mock_method.return_value.execute.side_effect = self.simple_3_page_response paging_message = 'Last item in page: %%last_item%%' - gapi.get_all_pages( - self.mock_service, - self.mock_method_name, - page_message=paging_message, - message_attribute='position') + with patch.object(gapi.sys.stderr, 'write') as mock_write: + gapi.get_all_pages( + self.mock_service, + self.mock_method_name, + page_message=paging_message, + message_attribute='position') messages_written = [ call_args[0][0] for call_args in mock_write.call_args_list