diff --git a/changelog/3632.feature.rst b/changelog/3632.feature.rst
index a08a6dd61..a715288e1 100644
--- a/changelog/3632.feature.rst
+++ b/changelog/3632.feature.rst
@@ -1 +1 @@
-Richer comparison information on ``AssertionError`` for objects created using `attrs `_ or `dataclasses `_ (Python 3.7+).
+Richer comparison introspection on ``AssertionError`` for objects created using `attrs `_ or `dataclasses `_ (Python 3.7+).
diff --git a/doc/en/example/assertion/failure_demo.py b/doc/en/example/assertion/failure_demo.py
index 115fd3e22..10f8798f2 100644
--- a/doc/en/example/assertion/failure_demo.py
+++ b/doc/en/example/assertion/failure_demo.py
@@ -101,6 +101,30 @@ class TestSpecialisedExplanations(object):
text = "head " * 50 + "f" * 70 + "tail " * 20
assert "f" * 70 not in text
+ def test_eq_dataclass(self):
+ from dataclasses import dataclass
+
+ @dataclass
+ class Foo(object):
+ a: int
+ b: str
+
+ left = Foo(1, "b")
+ right = Foo(1, "c")
+ assert left == right
+
+ def test_eq_attrs(self):
+ import attr
+
+ @attr.s
+ class Foo(object):
+ a = attr.ib()
+ b = attr.ib()
+
+ left = Foo(1, "b")
+ right = Foo(1, "c")
+ assert left == right
+
def test_attribute():
class Foo(object):
diff --git a/doc/en/example/assertion/test_failures.py b/doc/en/example/assertion/test_failures.py
index 9ffe31664..30ebc72dc 100644
--- a/doc/en/example/assertion/test_failures.py
+++ b/doc/en/example/assertion/test_failures.py
@@ -9,5 +9,5 @@ def test_failure_demo_fails_properly(testdir):
failure_demo.copy(target)
failure_demo.copy(testdir.tmpdir.join(failure_demo.basename))
result = testdir.runpytest(target, syspathinsert=True)
- result.stdout.fnmatch_lines(["*42 failed*"])
+ result.stdout.fnmatch_lines(["*44 failed*"])
assert result.ret != 0
diff --git a/src/_pytest/assertion/util.py b/src/_pytest/assertion/util.py
index da5d5fe97..ac83f6000 100644
--- a/src/_pytest/assertion/util.py
+++ b/src/_pytest/assertion/util.py
@@ -347,12 +347,12 @@ def _compare_eq_class(left, right, verbose, type=None):
if same and verbose < 2:
explanation += [u("Omitting %s identical items, use -vv to show") % len(same)]
elif same:
- explanation += [u("Common items:")]
+ explanation += [u("Common attributes:")]
explanation += pprint.pformat(same).splitlines()
if diff:
+ class_name = left.__class__.__name__
explanation += [("Differing attributes:")]
for k in diff:
- class_name = left.__class__.__name__
explanation += [
u("%s(%s=%r) != %s(%s=%r)")
% (class_name, k, getattr(left, k), class_name, k, getattr(right, k))
diff --git a/testing/test_assertion.py b/testing/test_assertion.py
index e7f3dbaf3..8ddd96b94 100644
--- a/testing/test_assertion.py
+++ b/testing/test_assertion.py
@@ -564,7 +564,7 @@ class TestAssert_reprcompare_dataclass(object):
lines = callequal(left, right)
assert lines[1].startswith("Omitting 1 identical item")
- assert "Common items" not in lines
+ assert "Common attributes" not in lines
for line in lines[1:]:
assert "field_a" not in line
@@ -581,7 +581,7 @@ class TestAssert_reprcompare_dataclass(object):
right = SimpleDataObject(1, "c")
lines = callequal(left, right, verbose=2)
- assert lines[1].startswith("Common items:")
+ assert lines[1].startswith("Common attributes:")
assert "Omitting" not in lines[1]
assert lines[2] == "['field_a']"
@@ -598,14 +598,14 @@ class TestAssert_reprcompare_dataclass(object):
right = SimpleDataObject(1, "b")
lines = callequal(left, right, verbose=2)
- assert lines[1].startswith("Common items:")
+ assert lines[1].startswith("Common attributes:")
assert "Omitting" not in lines[1]
assert lines[2] == "['field_a']"
for line in lines[2:]:
assert "field_b" not in line
@pytest.mark.skipif(sys.version_info < (3, 7), reason="Dataclasses in Python3.7+")
- def test_comparing_different_data_classes(self):
+ def test_comparing_two_different_data_classes(self):
from dataclasses import dataclass
@dataclass
@@ -637,7 +637,7 @@ class TestAssert_reprcompare_attrsclass(object):
lines = callequal(left, right)
assert lines[1].startswith("Omitting 1 identical item")
- assert "Common items" not in lines
+ assert "Common attributes" not in lines
for line in lines[1:]:
assert "field_a" not in line
@@ -651,7 +651,7 @@ class TestAssert_reprcompare_attrsclass(object):
right = SimpleDataObject(1, "c")
lines = callequal(left, right, verbose=2)
- assert lines[1].startswith("Common items:")
+ assert lines[1].startswith("Common attributes:")
assert "Omitting" not in lines[1]
assert lines[2] == "['field_a']"
@@ -665,13 +665,13 @@ class TestAssert_reprcompare_attrsclass(object):
right = SimpleDataObject(1, "b")
lines = callequal(left, right, verbose=2)
- assert lines[1].startswith("Common items:")
+ assert lines[1].startswith("Common attributes:")
assert "Omitting" not in lines[1]
assert lines[2] == "['field_a']"
for line in lines[2:]:
assert "field_b" not in line
- def test_comparing_different_attrs(self):
+ def test_comparing_two_different_attrs_classes(self):
@attr.s
class SimpleDataObjectOne:
field_a = attr.ib()