【问题标题】:AttributeError: 'ExceptionInfo' object has no attribute 'traceback' when using pytest to assert exceptionsAttributeError: 'ExceptionInfo' 对象在使用 pytest 断言异常时没有属性 'traceback'
【发布时间】:2018-12-21 18:33:10
【问题描述】:

我需要使用py.test 断言错误消息,

import pandas as pd
import numpy as np

from inv_exception_store import InvAmtValError

MAX_INV_VAL = 10000000.0
MIN_INV_VAL = 0.0


class Invoices:

    def __init__(self, data=None):
        if data is None:
            self.__invoices = pd.Series([], dtype=np.float32)
        else:
            self.__invoices = pd.Series(pd.Series(data).astype(np.float32))

    def addInvoice(self, amount):
        try:
            if self.__invoices.size > MAX_INV_SIZE:
                raise InvNumError
            elif amount > MAX_INV_VAL or amount < MIN_INV_VAL:
                raise InvAmtValError(amount)
            else:
                self.__invoices = self.__invoices.append(pd.Series(amount).astype(np.float32), ignore_index=True)
        except (InvNumError, InvAmtValError) as e:
            print(str(e))


class InvAmtValError(Exception):
    def __init__(self, amount, message=None):
        if message is None:
            if amount > 100000000.0:
                message = 'The invoice amount(s) {} is invalid since it is > $100,000,00.00'.format(amount)
            elif amount < 0.0:
                message = 'The invoice amount(s) {} is invalid since it is < $0.00'.format(amount)
            else:
                message = 'The invoice amount(s) {} is invalid'.format(amount)

        super(InvAmtValError, self).__init__(str(self.__class__.__name__) + ': ' + message)
        self.message = message

    def __str__(self):
        return self.message

class TestInvoice(object):
        def test_invalid_inv_amount_err(self):
            with pytest.raises(InvAmtValError) as e:
                invoices = Invoices()

                invoices.addInvoice(-1.2)

                assert str(e) == 'The invoice amount(s) -1.2 is invalid since it is < $0.00'

                invoices.addInvoice(100000000.1)

                assert str(e) == 'The invoice amount(s) 100000000.1 is invalid since it is > $100,000,00.00'

通过运行测试,我得到了,

self = <ExceptionInfo AttributeError tblen=2>

    def __str__(self):
>       entry = self.traceback[-1]
E       AttributeError: 'ExceptionInfo' object has no attribute 'traceback'

我想知道如何让py.test 在这里断言异常。

更新。尝试了建议的解决方案,

    def test_invalid_min_inv_amount_err(self):
        with pytest.raises(InvAmtValError) as e:
            invoices = Invoices()

            invoices.addInvoice(-1.2)
        assert str(e) == 'The invoice amount(s) -1.2 is invalid since it is < $0.00'
        assert e.type == InvAmtValError

得到

>           invoices.addInvoice(-1.2)
E           Failed: DID NOT RAISE

【问题讨论】:

    标签: python python-3.x pandas exception pytest


    【解决方案1】:

    您不能在 with pytest.raises 上下文中使用 ExceptionInfo。运行预期在上下文中引发的代码,使用外部的异常信息:

    with pytest.raises(InvAmtValError) as e:
        invoices = InvoiceStats()
        invoices.addInvoice(-1.2)
    
    assert str(e) == 'The invoice amount(s) -1.2 is invalid since it is < $0.00'
    assert e.type == InvAmtValError  # etc
    

    但是,如果您只想断言异常消息,惯用的方法是将预期消息直接传递给pytest.raises

    expected = 'The invoice amount(s) -1.2 is invalid since it is < $0.00'
    with pytest.raises(InvAmtValError, message=expected):
        invoices = InvoiceStats()
        invoices.addInvoice(-1.2)
    
    expected = 'The invoice amount(s) 100000000.1 is invalid since it is > $100,000,00.00'
    with pytest.raises(InvAmtValError, message=expected):
        invoices = InvoiceStats()
        invoices.addInvoice(100000000.1)
    

    更新。尝试了建议的解决方案,得到:

    >           invoices.addInvoice(-1.2)
    E           Failed: DID NOT RAISE
    

    这是因为在 addInvoice 方法中确实没有引发异常 - 它在 try 块内引发并在之后立即捕获。要么完全删除 try 块,要么重新引发异常:

    try:
        raise InvAmtValError(amount)
    except InvAmtValError as e:
        print(str(e))
        raise e
    

    【讨论】:

    • 尝试了第一种和第二种解决方案,但得到了&gt; invoices.addInvoice(-1.2) E Failed: DID NOT RAISE&gt; invoices.addInvoice(100000000.1) E Failed: DID NOT RAISE
    • 我已经修改了 OP,我在 Invoices 类上测试,而不是 InvoiceStats,但仍然收到上述消息,尽管它应该会捕获错误。
    • 我现在看到了。您的测试行为是正确的。再次查看addInvoice - 您在try 块中引发异常,因此引发异常并立即捕获并打印错误消息。如果您希望在方法中引发异常,请完全删除 try 块,或在 except 块中添加 raise e 以重新引发 catches 异常。
    • 感谢这个清晰的解释,我在阅读其他一些帖子后怀疑同样的事情。
    • 很高兴能帮上忙!好消息是编写测试是值得的,毕竟;-)
    猜你喜欢
    • 2022-10-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-29
    • 1970-01-01
    • 2022-06-14
    相关资源
    最近更新 更多