使用'unittest'进行Python测试 - 如何在测试中使用assertRaises?

17

我正在尝试使用'unittest'在Python中进行简单的测试,以查看类在构造函数接收到不适当的输入时是否会引发异常。该类如下:

class SummaryFormula:
    def __init__( self, summaryFormula):
        self.atoms = {}
        for atom in re.finditer( "([A-Z][a-z]{0,2})(\d*)", summaryFormula):
            symbol = atom.group(1)
            count = atom.group(2)

            if pocet != "":
                self.atoms[ symbol] = int(count)
            else:
                self.atoms[ symbol] = 1

我的测试如下:

    class ConstructorTestCase(unittest.TestCase):
      def testEmptyString(self):
        self.assertRaises(TypeError, ukol1.SummaryFormula(), "testtest")

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

我想要的只是测试失败,也就是说构造函数不适合输入的异常没有被处理。

但实际上,我得到了一个错误:__init__() takes exactly two arguments (1 given)

我错过了什么?我应该指定什么作为第二个参数?

还有,我应该使用什么类型的错误来处理传递给构造函数的与我的正则表达式不匹配的输入的异常?


我无法直接运行代码,因为在for循环附近有语法错误。你能纠正一下吗? - pyfunc
我认为for循环周围的缩进不正确。 - pyfunc
@pyfunc:非常抱歉,已更正。 - Tomas Novotny
5个回答

28
更Python化的方式是使用`with`命令(在Python 2.7中添加):
with self.assertRaises(SomeException):
    do_something()

Documentation: assertRaises


1
这实际上非常棒。漂亮而干净。 - jangeador

26

assertRaises 有点令人困惑,因为你需要提供可调用对象,而不是一个调用的表达式。

请将您的代码更改为:

self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")

在你的代码中,你正在手动调用构造函数,并且它引发了关于参数数量不足的异常。相反,你需要给assertRaises可调用对象(ukol1.SummaryFormula),以及调用该对象所需的参数("testtest")。然后,它可以调用它,捕获并检查异常。


13

那是因为在实例化对象时你的类需要一个参数。

当你传入

ukol1.SummaryFormula()

你应该将参数summaryFormula传递给它。

ukol1.SummaryFormula(someSummaryFormula)

混淆的原因在于你的类名为SummaryFormula,而你传递给__init__的参数也是SummaryFormula。

或者应该是这样的:

self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")

这当然是我尝试的第一件事,但如果我使用self.assertRaises(TypeError, ukol1.SummaryFormula("testtest"), "testtest"),我会得到另一个错误:SummaryFormula实例没有__call__方法。而且,在assertRaises中指定传递给测试函数的参数不是作为assertRaises()函数的第三个(或第四个、第五个等等)参数吗? - Tomas Novotny
1
@Tomas Novotny:我在尝试运行您的代码时添加了第二个更改。在此重复一下:self.assertRaises(TypeError, ukol1.SummaryFormula, "testtest")。 - pyfunc

7

其他答案都没有指出如何使用封装引发异常代码的上下文,以下是您可以这样做的方法。

with self.assertRaises(ValueError) as ctx:
    <some code that throws an exception>

expected_msg = 'foo_bar_baz'
self.assertEquals(ctx.exception.message, expected_msg)

在这个 unittest.case._AssertRaisesContext 中,我们感兴趣的属性有:

  • exception(异常)
  • expected(期望结果)
  • expected_regexp(期望结果正则表达式)
  • failureException(失败异常)

1
对我来说,ctx.exception没有'message'属性,但是self.assertEquals(str(ctx.exception), expected_msg)可以工作。 - Bryan Prazen

4
一种更通用的替代格式是:
args=['testtest']
kwargs = {}
self.assertRaises(TypeError, ukol1.SummaryFormula, *args, **kwargs)

如果你的构造函数是多态的,并且你想循环遍历一组不同方式的参数错误,这个功能就会非常有用,例如:

arg_lists = [
    ['testtest'],
    ['anothertest'],
    ['YAT'],
]
for args in arg_lists:
    self.assertRaises(TypeError, ukol1.SummaryFormula, *args)

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接