Python unittest是否立即报告错误?

1 投票
1 回答
511 浏览
提问于 2025-04-15 13:07

Python的unittest模块在报告错误时,是否总是严格按照测试代码中行的执行顺序来报告?错误会不会导致代码中的变量发生意想不到的变化?

我被unittest报告的一个KeyError搞得很困惑。出问题的那一行看起来没问题。在执行停止前的最后一行,调试打印的请求键和字典显示这个键确实在字典里。KeyError中提到的键是另一个键,但那也似乎在字典中。

我在外层循环中插入了一个计数器变量,以便在错误行之前打印外层循环的迭代次数(在内层循环中),结果输出的顺序和我预期的不一样。输出的结果是像0, 0, 0, 1, 1, 0, 0, 0, 1, 1, 1, 2, 2, 2这样的,而我本来期待的是0, 0, 0, 1, 1, 1, 2, 2, 2。调试打印的内部数据也显示从一个循环到下一个循环有意想不到的变化。

代码(包含许多调试行):

def onSave(screen_data):
    counter = 0
    for table, flds_dct in self.target_tables.items():
        print 'TABLE %s' % table
        print 'FIELDS: %s' % flds_dct['fields']
        tbl_screen_data = {}
        for fld in flds_dct['fields']:
            print 'LOOP TOP'
            print 'FIELD: %' % fld
            print 'SCREEN DATA: %s' % screen_data
            print 'COUNTER: %s' % counter
            print 'SCREEN DATA OUTPUT: %s' % screen_data[fld]
            tbl_screen_data[fld] = screen_data[fld]
            print 'LOOP BOTTOM'
        self.tables[table].addEntry(tbl_screen_data)
        counter =+ 1
        print 'OUTER LOOP BOTTOM'

在错误发生前,这里输出:

TABLE: questions
FIELDS: ['whatIsYourQuest', 'whatIsYourName', 'whatIsTheAirSpeedOfSwallow']
LOOP TOP
FIELD: whatIsYourQuest
SCREEN DATA: 
{'whatIsYourQuest': 'grail', 
 'whatIsYourName': 'arthur', 
 'whatIsYourFavouriteColour': 'blue', 
 'whatIsTheAirSpeedOfSwallow': 'african or european?', 
 'whatIsCapitalOfAssyria': 'Nineveh'}
    COUNTER: 1
    SCREEN DATA OUTPUT: grail
    LOOP BOTTOM
    OUTER LOOP BOTTOM

但随后执行停止,我得到了这个错误信息:

line 100, in writeData
    print 'SCREEN DATA OUTPUT: %s screen_data[fld]
KeyError: 'whatIsCapitalOfAssyria'

但这个错误被归因于一行已经打印过输出的代码,并且在错误行之后的几行输出后停止执行。

正如我之前提到的,进一步调试显示screen_data的内容在循环的迭代中发生了变化。关键的是,传入的字典没有键'whatIsCapitalOfAssyria'。

缺少这个键是错误的原因。在某个时刻,代码询问screen_data字典'whatIsCapitalOfAssyria',但它无法回答,因此当然就出错了。但是,当调试行输出的screen_data对象确实有这个键时,这一点很难看出来;而且错误条件的报告是在执行了更多行之后才被触发,这让检查错误相关的值变得混乱。

那么unittest是如何处理代码错误的呢?我在这里做错了什么?我应该如何使用它以避免这种情况?

编辑:我可能应该补充一下,被测试的方法会触发对其他多个方法的调用,而这些方法又会触发自己的调用。我认为这些方法的测试都还不错,但也许这些相互关联的调用数量是个问题。

1 个回答

1

我觉得你看到的错误是在你循环的下一步,而不是你看到所有输出的那一步。试着把普通的 print 改成 print>>stderr, 这样可以避免输出被缓存或者被压制的问题。

撰写回答