BaseException を継承していないため、モック例外をキャッチできません。質問する

BaseException を継承していないため、モック例外をキャッチできません。質問する

私は、リモート サーバーに接続し、応答を待機し、その応答に基づいてアクションを実行するプロジェクトに取り組んでいます。いくつかの異なる例外をキャッチし、キャッチされた例外に応じて異なる動作をします。例:

def myMethod(address, timeout=20):
    try:
        response = requests.head(address, timeout=timeout)
    except requests.exceptions.Timeout:
        # do something special
    except requests.exceptions.ConnectionError:
        # do something special
    except requests.exceptions.HTTPError:
        # do something special
    else:
        if response.status_code != requests.codes.ok:
            # do something special
        return successfulConnection.SUCCESS

これをテストするために、次のようなテストを書きました。

class TestMyMethod(unittest.TestCase):

    def test_good_connection(self):
        config = {
            'head.return_value': type('MockResponse', (), {'status_code': requests.codes.ok}),
            'codes.ok': requests.codes.ok
        }
        with mock.patch('path.to.my.package.requests', **config):
            self.assertEqual(
                mypackage.myMethod('some_address',
                mypackage.successfulConnection.SUCCESS
            )

    def test_bad_connection(self):
        config = {
            'head.side_effect': requests.exceptions.ConnectionError,
            'requests.exceptions.ConnectionError': requests.exceptions.ConnectionError
        }
        with mock.patch('path.to.my.package.requests', **config):
            self.assertEqual(
                mypackage.myMethod('some_address',
                mypackage.successfulConnection.FAILURE
            )

関数を直接実行すると、すべてが期待どおりに動作します。関数の句raise requests.exceptions.ConnectionErrorを追加してテストもしましtryた。しかし、単体テストを実行すると、

ERROR: test_bad_connection (test.test_file.TestMyMethod)
----------------------------------------------------------------
Traceback (most recent call last):
  File "path/to/sourcefile", line ###, in myMethod
    respone = requests.head(address, timeout=timeout)
  File "path/to/unittest/mock", line 846, in __call__
    return _mock_self.mock_call(*args, **kwargs)
  File "path/to/unittest/mock", line 901, in _mock_call
    raise effect
my.package.requests.exceptions.ConnectionError

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "Path/to/my/test", line ##, in test_bad_connection
    mypackage.myMethod('some_address',
  File "Path/to/package", line ##, in myMethod
    except requests.exceptions.ConnectionError:
TypeError: catching classes that do not inherit from BaseException is not allowed

パッチを適用していた例外を変更しようとしましたBaseExceptionが、ほぼ同じエラーが発生しました。

もう読んだhttps://stackoverflow.com/a/18163759/3076272すでにそうなので、どこかに悪いフックがあるに違いないと思うのです__del__が、どこを探せばいいのか、その間に何ができるのかさえわかりません。また、私は比較的初心者なので、unittest.mock.patch()そこでも何か間違っている可能性が非常に高いです。

これは Fusion 360 アドインなので、Fusion 360 のパッケージ版 Python 3.3 を使用しています。私の知る限り、これはバニラ バージョン (つまり、独自に作成されていない) ですが、確信はありません。

ベストアンサー1

最小限の例でエラーを再現できました:

foo.py:

class MyError(Exception):
    pass

class A:
    def inner(self):
        err = MyError("FOO")
        print(type(err))
        raise err
    def outer(self):
        try:
            self.inner()
        except MyError as err:
            print ("catched ", err)
        return "OK"

モックなしでテストする:

class FooTest(unittest.TestCase):
    def test_inner(self):
        a = foo.A()
        self.assertRaises(foo.MyError, a.inner)
    def test_outer(self):
        a = foo.A()
        self.assertEquals("OK", a.outer())

はい、すべて順調です。両方のテストに合格しました

問題はモックにあります。クラス MyError がモックされるとすぐに、expect句は何もキャッチできなくなり、質問の例と同じエラーが発生します。

class FooTest(unittest.TestCase):
    def test_inner(self):
        a = foo.A()
        self.assertRaises(foo.MyError, a.inner)
    def test_outer(self):
        with unittest.mock.patch('foo.MyError'):
            a = exc2.A()
            self.assertEquals("OK", a.outer())

すぐに以下が与えられます:

ERROR: test_outer (__main__.FooTest)
----------------------------------------------------------------------
Traceback (most recent call last):
  File "...\foo.py", line 11, in outer
    self.inner()
  File "...\foo.py", line 8, in inner
    raise err
TypeError: exceptions must derive from BaseException

During handling of the above exception, another exception occurred:

Traceback (most recent call last):
  File "<pyshell#78>", line 8, in test_outer
  File "...\foo.py", line 12, in outer
    except MyError as err:
TypeError: catching classes that do not inherit from BaseException is not allowed

TypeErrorここで私はあなたが持っていなかった最初のものを手に入れました。なぜなら、あなたが'requests.exceptions.ConnectionError': requests.exceptions.ConnectionError設定で本当の例外を強制している間に私はモックを上げているからです。しかし、問題は残っています。このexcept節はモックをキャッチしようとする

TL/DR: パッケージ全体をモックするとrequestsexcept requests.exceptions.ConnectionError句はモックをキャッチしようとします。モックは実際には ではないためBaseException、エラーが発生します。

私が思いつく唯一の解決策は、全体をモックするのではなくrequests、例外ではない部分だけをモックすることです。モックする方法がわからなかったことを認めなければなりません。これ以外のすべてを嘲笑するしかし、あなたの例では、パッチを当てるだけで済みますrequests.head。したがって、これは機能するはずです:

def test_bad_connection(self):
    with mock.patch('path.to.my.package.requests.head',
                    side_effect=requests.exceptions.ConnectionError):
        self.assertEqual(
            mypackage.myMethod('some_address',
            mypackage.successfulConnection.FAILURE
        )

つまり、head副作用として例外のあるメソッドのみをパッチします。

おすすめ記事