summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTakashi Natsume <takanattie@gmail.com>2020-09-28 22:35:00 +0900
committerTakashi Natsume <takanattie@gmail.com>2020-09-28 23:08:15 +0900
commit8d3c2ce92bcaf8cf777bf29fd46275572da61547 (patch)
treeb13754b5b56b7607af61705da5d5212ffa6bdfb9
parent4acc112a308d0cedd5bfc00eb0621aba99e0d910 (diff)
downloadnova-8d3c2ce92bcaf8cf777bf29fd46275572da61547.tar.gz
Add a hacking rule for assert_has_calls
Add the following hacking rule. * N366: The assert_has_calls is a method rather than a variable. Not correct: mock_method.assert_has_calls = [mock.call(0)] Correct: mock_method.assert_has_calls([mock.call(0)]) This patch is a follow-up patch for Id094dd90efde09b9a835d4492f4a92b8f8ad296e. Change-Id: I892f8c23ee44f2b3518776a9705e3543f3115cae Signed-off-by: Takashi Natsume <takanattie@gmail.com>
-rw-r--r--HACKING.rst1
-rw-r--r--nova/hacking/checks.py17
-rw-r--r--nova/tests/unit/test_hacking.py24
-rw-r--r--tox.ini1
4 files changed, 43 insertions, 0 deletions
diff --git a/HACKING.rst b/HACKING.rst
index 6678328fd2..76ff4b6c22 100644
--- a/HACKING.rst
+++ b/HACKING.rst
@@ -67,6 +67,7 @@ Nova Specific Commandments
- [N363] Disallow ``(not_a_tuple)`` because you meant ``(a_tuple_of_one,)``.
- [N364] Check non-existent mock assertion methods and attributes.
- [N365] Check misuse of assertTrue/assertIsNone.
+- [N366] The assert_has_calls is a method rather than a variable.
Creating Unit Tests
-------------------
diff --git a/nova/hacking/checks.py b/nova/hacking/checks.py
index 65a63f1eb5..4bdba6991b 100644
--- a/nova/hacking/checks.py
+++ b/nova/hacking/checks.py
@@ -127,6 +127,8 @@ mock_attribute_re = re.compile(r"[\.\(](retrun_value)[,=\s]")
# Regex for useless assertions
useless_assertion_re = re.compile(
r"\.((assertIsNone)\(None|(assertTrue)\((True|\d+|'.+'|\".+\")),")
+# Regex for misuse of assert_has_calls
+mock_assert_has_calls_re = re.compile(r"\.assert_has_calls\s?=")
class BaseASTChecker(ast.NodeVisitor):
@@ -922,3 +924,18 @@ def useless_assertion(logical_line, filename):
match = useless_assertion_re.search(logical_line)
if match:
yield (0, msg % (match.group(2) or match.group(3)))
+
+
+@core.flake8ext
+def check_assert_has_calls(logical_line, filename):
+ """Check misuse of assert_has_calls.
+
+ Not correct: mock_method.assert_has_calls = [mock.call(0)]
+ Correct: mock_method.assert_has_calls([mock.call(0)])
+
+ N366
+ """
+ msg = "N366: The assert_has_calls is a method rather than a variable."
+ if ('nova/tests/' in filename and
+ mock_assert_has_calls_re.search(logical_line)):
+ yield (0, msg)
diff --git a/nova/tests/unit/test_hacking.py b/nova/tests/unit/test_hacking.py
index 9222daa451..78b948fbb2 100644
--- a/nova/tests/unit/test_hacking.py
+++ b/nova/tests/unit/test_hacking.py
@@ -909,3 +909,27 @@ class HackingTestCase(test.NoDBTestCase):
self._assert_has_no_errors(
code, checks.useless_assertion,
filename="nova/tests/unit/test_context.py")
+
+ def test_check_assert_has_calls(self):
+ code = """
+ mock_method.assert_has_calls = [mock.call(1)]
+ mock_method2.assert_has_calls = [
+ mock.call(1), mock.call(2)]
+ """
+ errors = [(x + 1, 0, 'N366') for x in range(2)]
+ # Check errors in 'nova/tests' directory.
+ self._assert_has_errors(
+ code, checks.check_assert_has_calls,
+ expected_errors=errors, filename="nova/tests/unit/test_context.py")
+ # Check no errors in other than 'nova/tests' directory.
+ self._assert_has_no_errors(
+ code, checks.check_assert_has_calls,
+ filename="nova/compute/api.py")
+ code = """
+ mock_method.assert_has_calls([mock.call(1)])
+ mock_method2.assert_has_calls([
+ mock.call(1), mock.call(2)])
+ """
+ self._assert_has_no_errors(
+ code, checks.check_assert_has_calls,
+ filename="nova/tests/unit/test_context.py")
diff --git a/tox.ini b/tox.ini
index 1bb4087b7a..f2333b6e30 100644
--- a/tox.ini
+++ b/tox.ini
@@ -314,6 +314,7 @@ extension =
N363 = checks:did_you_mean_tuple
N364 = checks:nonexistent_assertion_methods_and_attributes
N365 = checks:useless_assertion
+ N366 = checks:check_assert_has_calls
paths =
./nova/hacking