结果看似相等时,Python unittest失败

时间:2016-02-26 10:11:16

标签: python unit-testing python-unittest

我正在对我刚刚放在一起的RPN计算器上运行一系列单元测试。这个计算器可以混合整数,浮点数和皮卡。我经常需要能够使用picas来计算我正在做的一些排版工作。

出于某种原因,我的一个单元测试失败了:

Failure
Traceback (most recent call last):
  File "/Users/andrew/Developer/pyRpn/test_rpn.py", line 112, in test_pica_subtracted_from_pica
    self.assertEqual(self.calc.rpn(['10p3', '2p1', '-']), ['8p2'])
AssertionError: Lists differ: ['8p2'] != ['8p2']

First differing element 0:
'8p2'
8p2

  ['8p2']

我不明白为什么。为简化起见,我将该列表从等式中取出并直接与字符串进行比较:

Failure
Expected :'8p2'
Actual   :'8p2'
 <Click to see difference>

Traceback (most recent call last):
  File "/Users/andrew/Developer/pyRpn/test_rpn.py", line 112, in test_pica_subtracted_from_pica
    self.assertEqual(self.calc.rpn(['10p3', '2p1', '-']).pop(), '8p2')
AssertionError: '8p2' != '8p2'

它仍然失败。我看不出为什么'8p2' != '8p2'。如果我点击查看差异,在PyCharm中运行,它告诉我没有差异,内容相同,但测试失败。它也从命令行失败。

我把同样的测试作为doctest:

"""
>>> RPN().rpn(['10p3', '2p1', '-'])
['8p2']
"""

它没有问题。

MCVE:

import re
import unittest


class Pica(object):
    def __init__(self, points):
        self.points = points

    def __repr__(self):
        whole_points = int(self.points / 12)
        sub_points = self.points - (whole_points * 12)
        return "'%rp%r'" % (whole_points, sub_points)

    def __sub__(self, other):
        if type(other) is Pica:
            return Pica(self.points - other.points)


class RPN:
    def __init__(self):
        self.oper_dict = {'-': RPN.pop_two_and_sub}
        self.pica_pattern = re.compile("(\d+)p(\d+)")

    def pop_two_and_sub(self, terms):
        terms.append(terms.pop() - terms.pop())

    def rpn(self, terms):
        result = []
        for term in terms:
            if term in self.oper_dict:
                self.oper_dict[term](self, result)
            elif self.pica_pattern.match(term):
                match = self.pica_pattern.match(term)
                result.append(Pica(int(match.group(1)) * 12 + int(match.group(2))))
            else:
                raise SyntaxError
        return result


class TestPica(unittest.TestCase):
    def test_pica_subtracted_from_pica(self):
        self.assertCountEqual(RPN().rpn(['2p1', '10p3', '-']), ['8p2'])


if __name__ == '__main__':
    unittest.main()

当我使用Python 3.5运行时,我收到以下错误:

Failure
Traceback (most recent call last):
  File "/Users/andrew/Developer/pyRpn/mvce.py", line 42, in test_pica_subtracted_from_pica
    self.assertCountEqual(RPN().rpn(['2p1', '10p3', '-']), ['8p2'])
AssertionError: Element counts were not equal:
First has 1, Second has 0:  '8p2'
First has 0, Second has 1:  '8p2'

2 个答案:

答案 0 :(得分:2)

好的,我找到了区别。 Python 3对unicode有更多的支持,但它没有显示打印unicode字符串时有效的编码,这就是为什么即使它们有不同的类型它们也会打印相同的内容:

  1. <class '__main__.Pica'>
  2. <class 'str'>
  3. 为了使断言起作用,要么需要更智能的比较,要么在调用assert方法之前需要将字符串放在通用格式中。

答案 1 :(得分:1)

结果显示相等,但它们不是。您没有比较字符串列表。 rpn()可以返回包含Pica个对象的列表:

>>> from rpn import RPN
>>> type(RPN().rpn(['2p1', '10p3', '-'])[0])
<class 'rpn.Pica'>

这表明rpn()返回的列表的第一个元素是Pica。因此,将Pica与字符串进行比较将返回False,因此您的断言将失败。

您可以在__eq__()课程中添加Pica方法,然后将PicaPica s进行比较:

def __eq__(self, other):
    """Test two Pica objects for equality"""
    return self.points == other.points

然后你可以在你的测试中做到这一点:

self.assertEqual(self.calc.rpn(['10p3', 2, '-']), [Pica(8*12+3)])

能够从字符串中创建Pica会很高兴:

def __init__(self, value):
    if isinstance(value, str):
        a,b = value.split('p')
        value = int(a) * 12 + int(b)
    self.points = value

现在你可以这样测试:

self.assertEqual(self.calc.rpn(['10p3', 2, '-']), [Pica('8p3')])