assertEqual(a, b) checks if a == b and return True or False,
The documentation says,
Test that first and second are equal. If the values do not compare
equal, the test will fail.
I'm running three tests with assertEqual on a simple class,
The class on test
class Car:
def __init__(self, name):
self.name = name
The TestCase
class CarTest(unittest.TestCase):
def test_diff_equal(self):
car1 = Car('Ford')
car2 = Car('Hyundai')
self.assertEqual(car1, car2)
def test_name_equal(self):
car1 = Car('Ford')
car2 = Car('Ford')
self.assertEqual(car1, car2)
def test_instance_equal(self):
car1 = Car('Ford')
self.assertEqual(car1, car1)
The results are
F.F
======================================================================
FAIL: test_diff_equal (cartest.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "cartest.py", line 10, in test_diff_equal
self.assertEqual(car1, car2)
AssertionError: <car.Car instance at 0x7f499ec12ef0> != <car.Car instance at 0x7f499ec12f38>
======================================================================
FAIL: test_name_equal (cartest.CarTest)
----------------------------------------------------------------------
Traceback (most recent call last):
File "cartest.py", line 15, in test_name_equal
self.assertEqual(car1, car2)
AssertionError: <car.Car instance at 0x7f499ec12fc8> != <car.Car instance at 0x7f499ec12f38>
----------------------------------------------------------------------
Ran 3 tests in 0.000s
FAILED (failures=2)
Is assertEqual used to check if both the instances are same? Or is anything wrong in my setup? Why did test_name_equal() fail?
Your test is working absolutely fine, and it's found a bug. Hurray!
Your two Car objects may have the same name, but why would that mean that they are the same car? Nothing in your code makes that so.
If you want that to be the case, implement __eq__ on the Car class:
def __eq__(self, other):
"""Return True if other is also a car and has the same name as
this one."""
return isinstance(other, Car) and self.name == other.name
Then that test should pass.
The whole question is reducible to "How Python compare objects" what is precisely defined in Section 5.9: Comparisons of official documentation.
Quoting from the official documentation (emphasis mine) to clarify on aspects you're asking of.
Most other objects of built-in types compare unequal unless they are
the same object; the choice whether one object is considered smaller
or larger than another one is made arbitrarily but consistently within
one execution of a program.
That's what's covered by test_instance_equal and what essentially is:
o1 = object()
o1 == o1 # will always be True
The operators <, >, ==, >=, <=, and != compare the values of two
objects. The objects need not have the same type. If both are numbers,
they are converted to a common type. Otherwise, objects of different
types always compare unequal, and are ordered consistently but
arbitrarily. You can control comparison behavior of objects of
non-built-in types by defining a cmp method or rich comparison
methods like gt, described in section Special method names.*
Quoting from special method names:
object.__lt__(self, other)
object.__le__(self, other)
object.__eq__(self, other)
object.__ne__(self, other)
object.__gt__(self, other)
object.__ge__(self, other)
New in version 2.1.
These are the so-called “rich comparison” methods, and are called for
comparison operators in preference to __cmp__() below. The
correspondence between operator symbols and method names is as
follows: (...) x==y calls x.__eq__(y), (...)
That's what test_diff_equal and test_name_equal shows. There isn't any __eq__ magic method defined, and therefore it falls back to the default implementation (they compare unequal unless they are the same object).
The question has nothing to do with unit testing a module.
Adding to what's been already said: For the example given, you'll need to directly compare the attributes of the objects, and not the objects themselves, for unittest.TestCase.assertEqual to work.
class CarTest(unittest.TestCase):
def test_diff_equal(self):
car1 = Car('Ford')
car2 = Car('Hyundai')
self.assertEqual(car1.name, car2.name)
def test_name_equal(self):
car1 = Car('Ford')
car2 = Car('Ford')
self.assertEqual(car1.name, car2.name)
def test_instance_equal(self):
car1 = Car('Ford')
self.assertEqual(car1.name, car1.name)
This should now work (and fail) as expected.
Related
I ran into an interesting situation with the unittest.TestCase.assertItemsEqual function under Python 2; posting my findings here for posterity.
The following unit test breaks under Python 2 when it should succeed:
import unittest
class Foo(object):
def __init__(self, a=1, b=2):
self.a = a
self.b = b
def __repr__(self):
return '({},{})'.format(self.a, self.b)
def __eq__(self, other):
return self.a == other.a and self.b == other.b
def __lt__(self, other):
return (self.a, self.b) < (other.a, other.b)
class Test(unittest.TestCase):
def test_foo_eq(self):
self.assertEqual(sorted([Foo()]), sorted([Foo()]))
self.assertItemsEqual([Foo()], [Foo()])
unittest.main()
Here is the output:
======================================================================
FAIL: test_foo_eq (__main__.Test)
----------------------------------------------------------------------
Traceback (most recent call last):
File "/home/tsanders/scripts/one_offs/test_unittest_assert_items_equal2.py", line 17, in test_foo_eq
self.assertItemsEqual([Foo()], [Foo()])
AssertionError: Element counts were not equal:
First has 1, Second has 0: (1,2)
First has 0, Second has 1: (1,2)
----------------------------------------------------------------------
Ran 1 test in 0.000s
FAILED (failures=1)
This is pretty confusing since the docs state:
It [assertItemsEqual] is the equivalent of assertEqual(sorted(expected), sorted(actual)) but it works with sequences of unhashable objects as well.
The same test passes under Python 3 (after swapping self.assertItemsEqual for self.assertCountEqual, since the name has changed).
EDIT: After posting this question, I did find this other question that covers the situation where neither __eq__ nor __hash__ is defined.
To get the test passing under both Python 2 and 3, I had to add the line __hash__ = None to Foo.
The assertItemsEqual/assertCountEqual function takes different code paths depending on whether or not the items in each list are hashable. And according to the docs:
If a class does not define a __cmp__() or __eq__() method it should not define a __hash__() operation either; if it defines __cmp__() or __eq__() but not __hash__(), its instances will not be usable in hashed collections.
With that in mind, Python 2 and 3 have different behavior with regard to __hash__ when __eq__ is defined:
In Python 2, defining __eq__ does not affect the default-provided __hash__, but trying to use the item in a hashed container results in implementation-defined behavior (e.g. keys may be duplicated because they have different hashes, even if __eq__ would return True).
In Python 3, defining __eq__ sets __hash__ to None.
As of Python 2.6, __hash__ can be explicitly set to None to make a class unhashable. In my case, this was required to get assertItemsEqual to use the correct comparison algorithm that relies on __eq__ instead of __hash__.
If I have the code my_object = object() in Python, will my_object be equal to anything except for itself?
I suspect the answer lies in the __eq__ method of the default object returned by object(). What is the implementation of __eq__ for this default object?
EDIT: I'm using Python 2.7, but am also interested in Python 3 answers. Please clarify whether your answer applies to Python 2, 3, or both.
object().__eq__ returns the NotImplemented singleton:
print(object().__eq__(3))
NotImplemented
By the reflexive rules of rich comparisons, when NotImplemented is returned, the "reflected" operation is tried. So if you have an object on the RHS that returns True for that comparison, then you can get a True response even though the LHS did not implement the comparison.
class EqualToEverything(object):
def __eq__(self,other):
return True
ete = EqualToEverything()
ete == object() # we implemented `ete.__eq__`, so this is obviously True
Out[74]: True
object() == ete # still True due to the reflexive rules of rich comparisons
Out[75]: True
python 2 specific bit: if neither object implements __eq__, then python moves on to check if either implement __cmp__. Equivalent reflexive rules apply here.
class ComparableToEverything(object):
def __cmp__(self,other):
return 0
cte = ComparableToEverything()
cte == object()
Out[5]: True
object() == cte
Out[6]: True
__cmp__ is gone in python 3.
In both python 2 and 3, when we exhaust all of these comparison operators and all are NotImplemented, the final fallback is checking identity. (a is b)
object doesn't implement __eq__, so falls back on the default comparison id(x) == id(y), i.e. are they the same object instance (x is y)?
As a new instance is created every time you call object(), my_object will never* compare equal to anything except itself.
This applies to both 2.x and 3.x:
# 3.4.0
>>> object().__eq__(object())
NotImplemented
# 2.7.6
>>> object().__eq__(object())
Traceback (most recent call last):
File "<pyshell#60>", line 1, in <module>
object().__eq__(object())
AttributeError: 'object' object has no attribute '__eq__'
* or rather, as roippi's answer points out, hardly ever, assuming sensible __eq__ implementations elsewhere.
I have a Cell class
class Cell :
def __init__(self,char):
self.char=char
self.image='_'
def __str__(self):
return self.image
def __eq__(self,other):
return self.image == other.image
def __ne__(self,other):
return not self.image == other.image
then I have two Cell objects a and b, why I can use expression like "if a != b:" to compare these two object. How does b get inside of a and call the eq method to make the comparison
b doesn't get inside. When an operator is used, Python first looks for the magic method on the left-hand argument. If the appropriate magic method is defined there, it is called. If it doesn't return NotImplemented, then that's the result. If the method doesn't exist (or it returns NotImplemented), then the magic method is called on the right-hand argument. (For arithmetic operators, the right-hand arguments gets a separate method, __radd__ being the right-hand version pf __add__, __rsub__ for __sub__, etc.).
So in your version, it calls __ne__ on a and that's it. The magic method is never called on b.
This behavior is described in the documentation.
Saying if a == b is equivalent to if a.__eq__(b).
Likewise, saying if a != b is really if a.__ne__(b). Both methods return boolean values.
Each class inherits default special methods for comparing equality and inequality, but these can be overridden if explicitly defined.
The other answers are the proper answer.
I just wanted to mention that __ne__ has a bug related to precedence. It should be defined as:
return not (self.image == other.image)
Which is best expressed as:
return not (self == other)
Don't Repeat Yourself.
Is it possible to use assert_equal to compare objects? I keep seeing this error:
AssertionError: <ex49.parser.Sentence object at 0x01F1BAF0> !=
<ex49.parser.Sentence object at 0x01F1BB10>
The relevant code fragment:
def test_parse_subject():
testsentence = "princess go east"
result = lexicon.scan(testsentence)
Sent = parse_sentence(result)
ResultSent = Sentence(('subject', 'princess'),
('verb', 'go'),
('object', 'east'))
print ResultSent.subject
print ResultSent.verb
print ResultSent.object
print Sent.subject
print Sent.verb
print Sent.object
assert_equal(Sent, ResultSent)
The print outputs on screen suggests that the objects have the same contents - yet the assertion error shows up. Why is this? Is there some way to use assert_equal to override this?
I believe you need to implement the __eq__ method on the Sentence class.
assertEqual(first, second, msg=None)¶
Test that first and second are equal. If the values do not compare equal, the test will fail.
In addition, if first and second are the exact same type and one of list, tuple, dict, set, frozenset or unicode or any type that a subclass registers with addTypeEqualityFunc() the type-specific equality function will be called in order to generate a more useful default error message (see also the list of type-specific methods).
Python unittest documentation
The correspondence between operator symbols and method names is as follows: xlt(y), x<=y calls x.le(y), x==y calls x.eq(y), x!=y and x<>y call x.ne(y), x>y calls x.gt(y), and x>=y calls x.ge(y).
Python data model documentation
An example:
import unittest
class A:
def __init__(self, num):
self.num = num
def __eq__(self, other):
return self.num == other.num
class Test(unittest.TestCase):
def test(self):
a1 = A(1)
a12 = A(1)
a2 = A(2)
self.assertEqual(a1, a1, 'a1 != a1')
self.assertEqual(a1, a12, 'a1 != a12')
self.assertEqual(a1, a2, 'a1 != a2')
def main():
unittest.TestRunner(Test())
if __name__ == '__main__':
unittest.main()
Now comment the __eq__ method and see the difference.
This is good info, For me, I was too lazy to search so I just compared the variables of the two objects as below:
def test_parse_subject():
word_list_a = lexicon.scan("eat the bear")
Sentence1 = Sentence(('noun','player'),('verb', 'eat'),('noun', 'bear'))
Sentence2 = parse_subject(word_list_a,('noun','player'))
assert_equal(Sentence2.subject, Sentence1.subject)
assert_equal(Sentence2.verb, Sentence1.verb)
assert_equal(Sentence2.object, Sentence1.object)
I too am working through LPTHW ex49. Specifically for the context of this example, I was able to get it to work by adding the __eq__() method to the Sentence class, as follows:
Class Sentence(object):
def __init__(self, subject, verb, object_)
...
def __eq__(self, other):
return (self.subject == other.subject and
self.verb == other.verb and
self.object_ == other.object_)
Then, in the test file, I did:
# where LIST5 is defined above to give list of two tuples, [('verb', 'go'), ('direction', 'east')]
def test_parse_subject():
wordlist = list(LIST5)
sent = parse.Sentence(('noun', 'person'), ('verb'), ('go'), ('direction', 'east))
newsent = parse.parse_subject(wordlist, ('noun', 'person'))
assert_equal(newsent, sent)
As far as I can tell (new to this), assert_equal with nose and unittest will call the __eq__() method if it exists. In this case, the test is OK as long as the two objects have the same three values for subject, verb, object_. However, this took me a while to figure out, because I had a bug in my code, and the only thing nose would provide is the same error message that you received, even when I had the __eq__() method. That is, it provided "AssertionError: ...object at 0x... != ... object at 0x..." This misled me into thinking that the __eq__() method was not working, since it looked like it was comparing addresses. Not sure if there's a better way to do this.
NOTE: I renamed object to object_ because gedit was highlighting object as a python keyword. Not sure if this is recommended to use trailing underscore.
In my code, I've defined a class with its own repr method. The representation of the class should be a list.
def __repr__(self):
if self.front <= self.tail:
q = self._queue[self.front:self.tail+1]
elif self.front > self.tail:
q = self._queue[self.front:]
q.extend(self._queue[:self.tail + 1])
return (q.__repr__())
I've written the following unittest to test this method.
def test_enqueue(self):
q = BoundedQueue(1)
q.enqueue(1)
self.assertEqual(q, [1])
However, I end up with an assertion error:
Traceback (most recent call last):
File "test_internmatch_queue.py", line 13, in test_enqueue
self.assertEqual(q, [1])
AssertionError: [1] != [1]
I'm not sure what the problem is... to my human eyes, [1]==[1]! I've tried several other variations in my repr method (below), and they all returned errors as well.
return repr(q)
return str(q)
q is a BoundedQueue. [1] is a list. They can't be equal unless you override __eq__. repr is not used for equality testing.
As recursive states, __repr__ isn't used to detect whether two values are equal.
You have several options:
Define __eq__ which is what python calls to check equality. I don't recommend this as I don't really see a BoundedQueue as being equal to a list
Define an items() method which returns the list. Then check for equality against the list
Add a way to build a BoundedQueue from a list. Then write __eq__ to check for equality between two BoundedQueues.