1. ホーム
  2. python

[解決済み] Python2.7でunittestのassertRaises()で捕捉したエラーメッセージを表示する方法は?

2022-12-21 16:21:39

質問

私のモジュールからのエラーメッセージが有益であることを確認するために、私はassertRaises()によって捕らえられたすべてのエラーメッセージを見たいと思います。今日、私はassertRaises()ごとにそれを行うが、テストコードにそれらの多くがあるので、それは非常に退屈になる。

どうすればすべてのassertRaises()のエラーメッセージを表示することができるでしょうか?のドキュメントを勉強しました。 http://docs.python.org/library/unittest.html のドキュメントを勉強しましたが、解決する方法が分かりませんでした。assertRaises() メソッドを何とかモンキーパッチできないでしょうか?私はテストコードを標準的な方法で使用することが最も多いので、テストコードのすべてのassertRaises()行を変更しないことを好んでいます。

この質問は、次のことに関連していると思います。 Pythonのunittest:どのように私は例外の引数をテストするのですか?

今日はこんな感じでやってます。たとえば、次のようになります。

#!/usr/bin/env python

def fail():
    raise ValueError('Misspellled errrorr messageee')

そして、テストコード。

#!/usr/bin/env python
import unittest
import failure   

class TestFailureModule(unittest.TestCase):

    def testFail(self):
        self.assertRaises(ValueError, failure.fail)

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

エラーメッセージを確認するには、assertRaises() のエラータイプを IOError などに変更するだけです。そうすると、エラーメッセージを見ることができます。

 E
======================================================================
ERROR: testFail (__main__.TestFailureModule)
----------------------------------------------------------------------
Traceback (most recent call last):
 File "test_failure.py", line 8, in testFail
   self.assertRaises(IOError, failure.fail)
  File "/usr/lib/python2.7/unittest/case.py", line 471, in assertRaises
    callableObj(*args, **kwargs)
 File "/home/jonas/Skrivbord/failure.py", line 4, in fail
    raise ValueError('Misspellled errrorr messageee')
ValueError: Misspellled errrorr messageee

----------------------------------------------------------------------
Ran 1 test in 0.001s

FAILED (errors=1)

何か提案はありますか? /Jonas

EDITです。

Robert Rossneyからのヒントで、なんとか問題を解決することができました。これは主にスペルミスのためではなく、エラーメッセージがモジュールのユーザーにとって本当に意味のあるものであることを確認するためです。unittest の通常の機能 (これは私がほとんどの場合使用する方法です) は、SHOW_ERROR_MESSAGES = False を設定することによって実現されます。

私は以下のように、assertRaises()メソッドを単純にオーバーライドします。これは魅力的なように動作します!

SHOW_ERROR_MESSAGES = True

class NonexistantError(Exception):
    pass

class ExtendedTestCase(unittest.TestCase):
    def assertRaises(self, excClass, callableObj, *args, **kwargs):
        if SHOW_ERROR_MESSAGES:
            excClass = NonexistantError
        try:
            unittest.TestCase.assertRaises(self, excClass, callableObj, *args, **kwargs)
        except:
            print '\n    ' + repr(sys.exc_info()[1]) 

結果の出力の一部分。

testNotIntegerInput (__main__.TestCheckRegisteraddress) ... 
    TypeError('The registeraddress must be an integer. Given: 1.0',)

    TypeError("The registeraddress must be an integer. Given: '1'",)

    TypeError('The registeraddress must be an integer. Given: [1]',)

    TypeError('The registeraddress must be an integer. Given: None',)
ok
testCorrectNumberOfBytes (__main__.TestCheckResponseNumberOfBytes) ... ok
testInconsistentLimits (__main__.TestCheckNumerical) ... 
    ValueError('The maxvalue must not be smaller than minvalue. Given: 45 and 47, respectively.',)

    ValueError('The maxvalue must not be smaller than minvalue. Given: 45.0 and 47.0, respectively.',)
ok
testWrongValues (__main__.TestCheckRegisteraddress) ... 
    ValueError('The registeraddress is too small: -1, but minimum value is 0.',)

    ValueError('The registeraddress is too large: 65536, but maximum value is 65535.',)
ok
testTooShortString (__main__.TestCheckResponseWriteData) ... 
    ValueError("The payload is too short: 2, but minimum value is 4. Given: '\\x00X'",)

    ValueError("The payload is too short: 0, but minimum value is 4. Given: ''",)

    ValueError("The writedata is too short: 1, but minimum value is 2. Given: 'X'",)

    ValueError("The writedata is too short: 0, but minimum value is 2. Given: ''",)
ok
testKnownValues (__main__.TestCreateBitPattern) ... ok
testNotIntegerInput (__main__.TestCheckSlaveaddress) ... 
    TypeError('The slaveaddress must be an integer. Given: 1.0',)

    TypeError("The slaveaddress must be an integer. Given: '1'",)

    TypeError('The slaveaddress must be an integer. Given: [1]',)

    TypeError('The slaveaddress must be an integer. Given: None',)
ok

どのように解決するのですか?

既成概念にとらわれない unittest はこれを行いません。 もしこれが頻繁にやりたいことであれば、次のようなことを試してみてください。

class ExtendedTestCase(unittest.TestCase):

  def assertRaisesWithMessage(self, msg, func, *args, **kwargs):
    try:
      func(*args, **kwargs)
      self.assertFail()
    except Exception as inst:
      self.assertEqual(inst.message, msg)

ユニットテストクラスを ExtendedTestCase の代わりに unittest.TestCase .

しかし、本当に、単にスペルミスのエラーメッセージを気にしていて、それを中心にテストケースを作りたいと思うほど気にしているなら、メッセージを文字列リテラルとしてインライン化すべきではないでしょう。 他の重要な文字列と同じように、インポートしたモジュールの定数として定義し、誰かがそれを校正する責任を負うべきです。 コードの中で単語のスペルを間違える開発者は、テストケースの中でもスペルを間違えます。