web-dev-qa-db-ja.com

Python unittest-assertRaisesの反対?

特定の状況で例外が発生しないことを確認するテストを作成します。

例外isが発生したかどうかをテストするのは簡単です...

sInvalidPath=AlwaysSuppliesAnInvalidPath()
self.assertRaises(PathIsNotAValidOne, MyObject, sInvalidPath) 

...しかし、どうすればoppositeを実行できますか。

このような私は私が何を求めているのか...

sValidPath=AlwaysSuppliesAValidPath()
self.assertNotRaises(PathIsNotAValidOne, MyObject, sValidPath) 
308
glaucon
def run_test(self):
    try:
        myFunc()
    except ExceptionType:
        self.fail("myFunc() raised ExceptionType unexpectedly!")
322
DGH

こんにちは-特定の状況で例外が発生しないことを確認するテストを作成したいと思います。

これがデフォルトの前提です。例外は発生しません。

他に何も言わない場合、それはすべてのテストで想定されています。

実際にアサーションを書く必要はありません。

58
S.Lott

関数を呼び出すだけです。例外が発生した場合、単体テストフレームワークはこれにエラーのフラグを付けます。コメントを追加したい場合があります、例えば:

sValidPath=AlwaysSuppliesAValidPath()
# Check PathIsNotAValidOne not thrown
MyObject(sValidPath)
50
user9876

私は元のポスターであり、コードで最初に使用したことなく、DGHによる上記の回答を受け入れました。

一度使用すると、実際に必要なことを実際に行うには少し調整が必要であることに気付きました(DGHに公平にするために、彼/彼女は「または類似の何か」と言っていました!)。

他の人のために、ここにTweakを投稿する価値があると思いました。

    try:
        a = Application("abcdef", "")
    except pySourceAidExceptions.PathIsNotAValidOne:
        pass
    except:
        self.assertTrue(False)

ここでやろうとしていたことは、スペースの2番目の引数でApplicationオブジェクトをインスタンス化しようとした場合に、pySourceAidExceptions.PathIsNotAValidOneが発生することを確認することでした。

上記のコード(DGHの回答に大きく基づいている)を使用すると、それができると信じています。

13
glaucon

assertNotRaisesモジュールの元のassertRaisesの実装の約90%を再利用することで、unittestを定義できます。このアプローチでは、assertNotRaisesメソッドになります。このメソッドは、失敗した状態を逆にすると、assertRaisesと同じように動作します。

TLDRとライブデモ

assertNotRaisesメソッドをunittest.TestCaseに追加するのは驚くほど簡単であることがわかりました(この答えを書くのにコードを書くのに比べて約4倍の時間がかかりました)。 実行中のassertNotRaisesメソッドのライブデモ です。 assertRaisesと同様 の場合、呼び出し可能変数と引数をassertNotRaisesに渡すか、withステートメントで使用できます。ライブデモには、assertNotRaisesが意図したとおりに機能することを示すテストケースが含まれています。

詳細

assertRaisesでのunittestの実装はかなり複雑ですが、少し巧妙なサブクラスを使用することで、その障害状態をオーバーライドして元に戻すことができます。

assertRaisesは、基本的にunittest.case._AssertRaisesContextクラスのインスタンスを作成して返す短いメソッドです(unittest.caseモジュールの定義を参照)。 _AssertNotRaisesContextをサブクラス化し、その_AssertRaisesContextメソッドをオーバーライドすることにより、独自の__exit__クラスを定義できます。

import traceback
from unittest.case import _AssertRaisesContext

class _AssertNotRaisesContext(_AssertRaisesContext):
    def __exit__(self, exc_type, exc_value, tb):
        if exc_type is not None:
            self.exception = exc_value.with_traceback(None)

            try:
                exc_name = self.expected.__name__
            except AttributeError:
                exc_name = str(self.expected)

            if self.obj_name:
                self._raiseFailure("{} raised by {}".format(exc_name,
                    self.obj_name))
            else:
                self._raiseFailure("{} raised".format(exc_name))

        else:
            traceback.clear_frames(tb)

        return True

通常、テストケースクラスは、TestCaseから継承することで定義します。代わりにサブクラスMyTestCaseから継承する場合:

class MyTestCase(unittest.TestCase):
    def assertNotRaises(self, expected_exception, *args, **kwargs):
        context = _AssertNotRaisesContext(expected_exception, self)
        try:
            return context.handle('assertNotRaises', args, kwargs)
        finally:
            context = None

これで、すべてのテストケースでassertNotRaisesメソッドを使用できるようになります。

5
tel

例外クラスをassertRaises()に渡すと、コンテキストマネージャーが提供されます。これにより、テストの読みやすさが向上します。

# raise exception if Application created with bad data
with self.assertRaises(pySourceAidExceptions.PathIsNotAValidOne):
    application = Application("abcdef", "")

これにより、コード内のエラーケースをテストできます。

この場合、無効なパラメーターをApplicationコンストラクターに渡すときにPathIsNotAValidOneが発生することをテストしています。

1
hiwaylon

次のようにunittestをモンキーパッチすると便利だとわかりました。

def assertMayRaise(self, exception, expr):
  if exception is None:
    try:
      expr()
    except:
      info = sys.exc_info()
      self.fail('%s raised' % repr(info[0]))
  else:
    self.assertRaises(exception, expr)

unittest.TestCase.assertMayRaise = assertMayRaise

これにより、例外がないかどうかをテストする際の意図が明確になります。

self.assertMayRaise(None, does_not_raise)

これにより、ループでのテストも簡単になります。

# ValueError is raised only for op(x,x), op(y,y) and op(z,z).
for i,(a,b) in enumerate(itertools.product([x,y,z], [x,y,z])):
  self.assertMayRaise(None if i%4 else ValueError, lambda: op(a, b))
1
AndyJost
def _assertNotRaises(self, exception, obj, attr):                                                                                                                              
     try:                                                                                                                                                                       
         result = getattr(obj, attr)                                                                                                                                            
         if hasattr(result, '__call__'):                                                                                                                                        
             result()                                                                                                                                                           
     except Exception as e:                                                                                                                                                     
         if isinstance(e, exception):                                                                                                                                           
            raise AssertionError('{}.{} raises {}.'.format(obj, attr, exception)) 

パラメータを受け入れる必要がある場合は変更できます。

のように呼び出す

self._assertNotRaises(IndexError, array, 'sort')
0
znotdead

あなたはそのように試すことができます。 try:self.assertRaises(None、function、arg1、arg2)例外:tryブロック内にコードを配置しない場合は、例外 'AssertionError:None not raised "を通過し、テストケースは失敗します。テストケースは合格です予期される動作であるtryブロック内に配置した場合。

0
lalit