1. ホーム
  2. unit-testing

[解決済み] tornado + async defのunittestはどのように行うのですか?

2022-02-07 15:20:50

質問

環境は?Python 3、トルネード4.4。メソッドが非同期なので、通常のunittestsは使えません。ttp://www.tornadoweb.org/en/stable/testing.html、非同期コードのユニットテストの方法を説明しているものがあります。しかし、それはトルネードコルーチンONLYで動作します。私がテストしたいクラスは、asyncのdef文を使っているので、この方法ではテストできません。例えば、ASyncHTTPClient.fetchとそのコールバックパラメータを使用するテストケースは以下のとおりです。

class MyTestCase2(AsyncTestCase):
    def test_http_fetch(self):
        client = AsyncHTTPClient(self.io_loop)
        client.fetch("http://www.tornadoweb.org/", self.stop)
        response = self.wait()
        # Test contents of response
        self.assertIn("FriendFeed", response.body)

しかし、私のメソッドはこのように宣言されています。

クラスConnection: async def get_data(url, *args): # ....

そして、コールバックはありません。テストケースからこのメソッドを呼び出すにはどうすればいいでしょうか?

UPDATEしてください。 Jessieの回答に基づいて、このMWEを作成しました。

import unittest

from tornado.httpclient import AsyncHTTPClient
from tornado.testing import AsyncTestCase, gen_test, main


class MyTestCase2(AsyncTestCase):
    @gen_test
    async def test_01(self):
        await self.do_more()

    async def do_more(self):
        self.assertEqual(1+1, 2)

main()

その結果、このようになります。

>py -3 -m test.py
E
======================================================================
ERROR: all (unittest.loader._FailedTest)
----------------------------------------------------------------------
AttributeError: module '__main__' has no attribute 'all'

----------------------------------------------------------------------
Ran 1 test in 0.000s

FAILED (errors=1)
[E 170205 10:05:43 testing:731] FAIL

トレースバックはありません。しかし、tornado.testing.main() を unittest.main() に置き換えると、突然動作し始めます。

でも、どうして?推測するに、asnycのユニットテストでは、tornado.testing.main( http://www.tornadoweb.org/en/stable/testing.html#tornado.testing.main )

混乱しています。

UPDATE 2: tornado.testingのバグです。回避策です。

all = MyTestCase2
main()

解決方法は?

self.wait / self.stopコールバックを使用する代わりに、"await"式の中で使用すれば、"fetch"が完了するのを待つことができます。

import unittest

from tornado.httpclient import AsyncHTTPClient
from tornado.testing import AsyncTestCase, gen_test


class MyTestCase2(AsyncTestCase):
    @gen_test
    async def test_http_fetch(self):
        client = AsyncHTTPClient(self.io_loop)
        response = await client.fetch("http://www.tornadoweb.org/")
        # Test contents of response
        self.assertIn("FriendFeed", response.body.decode())

unittest.main()

このコードで私がしなければならなかった他の変更は、バイトであるボディと文字列である "FriendFeed" を比較するために、ボディ上で "decode" を呼び出すということです。