簡體   English   中英

使用帶有Python assertRaises的上下文管理器

[英]Using a context manager with Python assertRaises

unittest的Python文檔暗示assertRaises()方法可以用作上下文管理器。 下面的代碼給出了一個Python文檔中單元測試的簡單示例。 testsample()方法中的assertRaises()調用工作正常。

現在我想在引發異常時訪問它,但是如果我將它注釋掉,而是取消注釋我嘗試使用上下文管理器的下一個塊,當我嘗試執行代碼時,我得到一個AttributeError: __exit__ 這適用於Python 2.7.2和3.2.2。 我可以try...except捕獲異常try...except塊並以這種方式訪問​​它,但是單元測試的文檔似乎意味着上下文管理器也會這樣做。

還有別的我在這里做錯了嗎?

class TestSequenceFunctions(unittest.TestCase):

    def setUp(self):
        self.seq = [x for x in range(10)]

    def testshuffle(self):
        # make sure the shuffled sequence does not lose any elements
        random.shuffle(self.seq)
        self.seq.sort()
        self.assertEqual(self.seq, [x for x in range(10)])

    def testchoice(self):
        element = random.choice(self.seq)
        self.assert_(element in self.seq)

    def testsample(self):
        self.assertRaises(ValueError, random.sample, self.seq, 20)

        # with self.assertRaises(ValueError, random.sample, self.seq, 20):
        #     print("Inside cm")

        for element in random.sample(self.seq, 5):
            self.assert_(element in self.seq)

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

似乎沒有人提出:

import unittest
# For python < 2.7, do import unittest2 as unittest

class Class(object):
    def should_raise(self):
        raise ValueError('expected arg')

class test_Class(unittest.TestCase):
    def test_something(self):
        DUT = Class()
        with self.assertRaises(ValueError) as exception_context_manager:
            DUT.should_raise()
        exception = exception_context_manager.exception

        self.assertEqual(exception.args, ('expected arg', ))

我通常使用e_cm作為exception_context_manager的縮寫。

unittest源代碼沒有顯示assertRaises的異常鈎子:

class _AssertRaisesContext(object):
    """A context manager used to implement TestCase.assertRaises* methods."""

    def __init__(self, expected, test_case, expected_regexp=None):
        self.expected = expected
        self.failureException = test_case.failureException
        self.expected_regexp = expected_regexp

    def __enter__(self):
        return self

    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is None:
            try:
                exc_name = self.expected.__name__
            except AttributeError:
                exc_name = str(self.expected)
            raise self.failureException(
                "{0} not raised".format(exc_name))
        if not issubclass(exc_type, self.expected):
            # let unexpected exceptions pass through
            return False
        self.exception = exc_value # store for later retrieval
        if self.expected_regexp is None:
            return True

        expected_regexp = self.expected_regexp
        if isinstance(expected_regexp, basestring):
            expected_regexp = re.compile(expected_regexp)
        if not expected_regexp.search(str(exc_value)):
            raise self.failureException('"%s" does not match "%s"' %
                     (expected_regexp.pattern, str(exc_value)))
        return True

因此,正如您所懷疑的那樣,如果您想要在保持assertRaises測試的同時攔截異常,那么構建您自己的try / except塊是可行的方法:

def testsample(self):
    with self.assertRaises(ValueError):
         try:
             random.sample(self.seq, 20)
         except ValueError as e:
             # do some action with e
             self.assertEqual(e.args,
                              ('sample larger than population',))
             # now let the context manager do its work
             raise                    

根據文件:

如果使用省略的callableObj或None調用,則返回上下文對象

所以代碼應該是:

with self.assertRaises(ValueError):
    random.sample(self.seq, 20)

考慮到這是六年前的問題,我想這是現​​在有效但當時沒有用的東西。 文檔說明這出現在2.7但不是微版本。

import unittest

class TestIntParser(unittest.TestCase):

    def test_failure(self):
        failure_message = 'invalid literal for int() with base 10'
        with self.assertRaises(ValueError) as cm:
            int('forty two')
        self.assertIn(failure_message, cm.exception.message)

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

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM