melony
melony

Reputation: 75

Learn Python the Hard Way, Ex 49 : Comparing objects using assert_equal

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?

Upvotes: 2

Views: 2759

Answers (3)

Francis Wafula
Francis Wafula

Reputation: 11

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)

Upvotes: 1

Steve Koch
Steve Koch

Reputation: 932

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.

Upvotes: 0

Pedro Salgado
Pedro Salgado

Reputation: 846

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.

Upvotes: 6

Related Questions