From caa3a67bde15964c08664b453d5c5bcc7698fba4 Mon Sep 17 00:00:00 2001 From: Arthur Hamon Date: Tue, 6 Aug 2019 01:57:13 +0200 Subject: [PATCH] feat(failure-message): reformat the message with the best requests matches (#459) The message is less verbose and the display is improved for a better readability. --- tests/unit/test_errors.py | 73 +++++++++++++++++++++++++++++++++++++ tests/unit/test_matchers.py | 8 +--- vcr/errors.py | 28 ++++++++------ vcr/matchers.py | 17 +-------- 4 files changed, 94 insertions(+), 32 deletions(-) create mode 100644 tests/unit/test_errors.py diff --git a/tests/unit/test_errors.py b/tests/unit/test_errors.py new file mode 100644 index 0000000..d4a9e99 --- /dev/null +++ b/tests/unit/test_errors.py @@ -0,0 +1,73 @@ +import pytest + +from vcr.compat import mock +from vcr import errors +from vcr.cassette import Cassette + + +@mock.patch("vcr.cassette.Cassette.find_requests_with_most_matches") +@pytest.mark.parametrize( + "most_matches, expected_message", + [ + # No request match found + ( + [], + "No similar requests, that have not been played, found." + ), + # One matcher failed + ( + [("similar request", ["method", "path"], [("query", "failed : query")])], + "Found 1 similar requests with 1 different matcher(s) :\n" + "\n1 - ('similar request').\n" + "Matchers succeeded : ['method', 'path']\n" + "Matchers failed :\n" + "query - assertion failure :\n" + "failed : query\n" + + ), + # Multiple failed matchers + ( + [("similar request", ["method"], [("query", "failed : query"), ("path", "failed : path")])], + "Found 1 similar requests with 2 different matcher(s) :\n" + "\n1 - ('similar request').\n" + "Matchers succeeded : ['method']\n" + "Matchers failed :\n" + "query - assertion failure :\n" + "failed : query\n" + "path - assertion failure :\n" + "failed : path\n" + + ), + # Multiple similar requests + ( + [ + ("similar request", ["method"], [("query", "failed : query")]), + ("similar request 2", ["method"], [("query", "failed : query 2")]) + ], + "Found 2 similar requests with 1 different matcher(s) :\n" + "\n1 - ('similar request').\n" + "Matchers succeeded : ['method']\n" + "Matchers failed :\n" + "query - assertion failure :\n" + "failed : query\n" + "\n2 - ('similar request 2').\n" + "Matchers succeeded : ['method']\n" + "Matchers failed :\n" + "query - assertion failure :\n" + "failed : query 2\n" + + ), + ] +) +def test_CannotOverwriteExistingCassetteException_get_message( + mock_find_requests_with_most_matches, most_matches, expected_message): + mock_find_requests_with_most_matches.return_value = most_matches + cassette = Cassette("path") + failed_request = "request" + exception_message = errors.CannotOverwriteExistingCassetteException._get_message( + cassette, "request" + ) + expected = "Can't overwrite existing cassette (%r) in your current record mode (%r).\n" \ + "No match for the request (%r) was found.\n" \ + "%s" % (cassette._path, cassette.record_mode, failed_request, expected_message) + assert exception_message == expected diff --git a/tests/unit/test_matchers.py b/tests/unit/test_matchers.py index 604b650..33181ae 100644 --- a/tests/unit/test_matchers.py +++ b/tests/unit/test_matchers.py @@ -204,17 +204,13 @@ def test_evaluate_matcher_does_not_match_with_assert_message(): def test_get_assertion_message(): - assert matchers.get_assertion_message(None) == "" + assert matchers.get_assertion_message(None) is None assert matchers.get_assertion_message("") == "" def test_get_assertion_message_with_details(): assertion_msg = "q1=1 != q2=1" - expected = ( - "--------------- DETAILS ---------------\n" - "{}\n" - "----------------------------------------\n".format(assertion_msg) - ) + expected = assertion_msg assert matchers.get_assertion_message(assertion_msg) == expected diff --git a/vcr/errors.py b/vcr/errors.py index bdccaca..107c6ae 100644 --- a/vcr/errors.py +++ b/vcr/errors.py @@ -5,21 +5,27 @@ class CannotOverwriteExistingCassetteException(Exception): message = self._get_message(kwargs["cassette"], kwargs["failed_request"]) super(CannotOverwriteExistingCassetteException, self).__init__(message) - def _get_message(self, cassette, failed_request): + @staticmethod + def _get_message(cassette, failed_request): """Get the final message related to the exception""" # Get the similar requests in the cassette that # have match the most with the request. best_matches = cassette.find_requests_with_most_matches(failed_request) - # Build a comprehensible message to put in the exception. - best_matches_msg = "" - for best_match in best_matches: - request, _, failed_matchers_assertion_msgs = best_match - best_matches_msg += "Similar request found : (%r).\n" % request - for failed_matcher, assertion_msg in failed_matchers_assertion_msgs: - best_matches_msg += "Matcher failed : %s\n" "%s\n" % ( - failed_matcher, - assertion_msg, - ) + if best_matches: + # Build a comprehensible message to put in the exception. + best_matches_msg = "Found {} similar requests with {} different matcher(s) :\n".format( + len(best_matches), len(best_matches[0][2])) + + for idx, best_match in enumerate(best_matches, start=1): + request, succeeded_matchers, failed_matchers_assertion_msgs = best_match + best_matches_msg += "\n%s - (%r).\n" \ + "Matchers succeeded : %s\n" \ + "Matchers failed :\n" % (idx, request, succeeded_matchers) + for failed_matcher, assertion_msg in failed_matchers_assertion_msgs: + best_matches_msg += "%s - assertion failure :\n" \ + "%s\n" % (failed_matcher, assertion_msg) + else: + best_matches_msg = "No similar requests, that have not been played, found." return ( "Can't overwrite existing cassette (%r) in " "your current record mode (%r).\n" diff --git a/vcr/matchers.py b/vcr/matchers.py index 8a04f7c..d74202d 100644 --- a/vcr/matchers.py +++ b/vcr/matchers.py @@ -135,21 +135,8 @@ def get_matchers_results(r1, r2, matchers): return matches_success, matches_fails -def get_assertion_message(assertion_details, **format_options): +def get_assertion_message(assertion_details): """ Get a detailed message about the failing matcher. """ - msg = "" - if assertion_details: - separator = format_options.get("separator", "-") - title = format_options.get("title", " DETAILS ") - nb_separator = format_options.get("nb_separator", 40) - first_title_line = ( - separator * ((nb_separator - len(title)) // 2) - + title - + separator * ((nb_separator - len(title)) // 2) - ) - msg += "{}\n{}\n{}\n".format( - first_title_line, str(assertion_details), separator * nb_separator - ) - return msg + return assertion_details