我有一个 Sanic 应用程序,可以对外部 api 进行一些异步调用。我希望编写一些模拟这些外部调用的单元测试。
正如我们从日志中看到的那样,在下面的代码中,测试确实通过了。然而,在他们完成 RuntimeError: this event loop is already running 后抛出
简化的 Sanic 应用程序:
app = Sanic(__name__)
app.config.from_pyfile('/usr/src/app/config.py')
Initialize(
app,
access_token_name='jwt',
authenticate=lambda: True,
claim_aud=app.config.AUTH_JWT_TOKEN['service']['audience'],
claim_iss=app.config.AUTH_JWT_TOKEN['service']['issuer'],
public_key=app.config.AUTH_JWT_TOKEN['service']['secret'],
responses_class=JWTResponses
)
@app.listener('before_server_start')
def init(app, loop):
ssl_ctx = ssl.SSLContext(ssl.PROTOCOL_TLS_CLIENT)
ssl_ctx.load_cert_chain(app.config.SSL_CERT, app.config.SSL_CERT_KEY)
ssl_ctx.load_verify_locations(app.config.SSL_SERVER_CERT)
ssl_ctx.check_hostname = False
ssl_ctx.verify_mode = ssl.CERT_REQUIRED
conn = aiohttp.TCPConnector(ssl_context=ssl_ctx)
app.aiohttp_session = aiohttp.ClientSession(loop=loop, connector=conn)
access_logger.disabled = True
@app.listener('after_server_stop')
def finish(app, loop):
loop.run_until_complete(app.aiohttp_session.close())
loop.close()
@app.route("endpoint/<mpn>")
@protected()
async def endpoint(request, mpn):
msg = msg(
mpn,
)
headers = {'content-type': 'text/xml'}
async with session.post(
config.URL,
data=msg.tostring(pretty_print=True, encoding='utf-8'),
headers=headers,
) as response:
response_text = await response.text()
try:
response = (
Response.from_xml(response_text)
)
return response
except ResponseException:
logger.error(e.get_message()['errors'][0]['message'])
return response.json(
e.get_message(),
status=HTTPStatus.INTERNAL_SERVER_ERROR
)
if __name__ == '__main__':
app.run(host="0.0.0.0", port=8000)
这是测试:
from server import app as sanic_app
@pytest.yield_fixture
def app():
app = sanic_app
yield app
@pytest.fixture
def test_cli(loop, app, sanic_client):
return loop.run_until_complete(sanic_client(app))
token = jwt.encode(
{
"iss": (
sanic_app.config.AUTH_JWT_TOKEN['service']
['issuer']
),
"aud": (
sanic_app.config.AUTH_JWT_TOKEN['service']
['audience']
),
"exp": datetime.datetime.utcnow() + datetime.timedelta(
seconds=int(100)
)
},
sanic_app.config.AUTH_JWT_TOKEN['service']['secret'],
algorithm='HS256'
).decode('utf-8')
token = 'Bearer ' + token
async def test_success(test_cli):
with aioresponses(passthrough=['http://127.0.0.1:']) as m:
with open('tests/data/summary.xml') as f:
data = f.read()
m.post(
'https://external_api',
status=200,
body=data
)
resp = await test_cli.get(
'endpoint/07000000000',
headers={"Authorization": token}
)
assert resp.status == 200
resp_json = await resp.json()
assert resp_json == {SOME_JSON}
如上所述,测试确实通过了,但随后抛出了错误。
================================================================================================= ERRORS ==================================================================================================
____________________________________________________________________________________ ERROR at teardown of test_success ____________________________________________________________________________________
tp = <class 'RuntimeError'>, value = None, tb = None
def reraise(tp, value, tb=None):
try:
if value is None:
value = tp()
if value.__traceback__ is not tb:
raise value.with_traceback(tb)
> raise value
/usr/local/lib/python3.6/site-packages/six.py:693:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
/usr/local/lib/python3.6/site-packages/six.py:693: in reraise
raise value
/usr/local/lib/python3.6/site-packages/six.py:693: in reraise
raise value
/usr/local/lib/python3.6/site-packages/pytest_sanic/plugin.py:212: in sanic_client
loop.run_until_complete(client.close())
uvloop/loop.pyx:1451: in uvloop.loop.Loop.run_until_complete
???
/usr/local/lib/python3.6/site-packages/pytest_sanic/utils.py:230: in close
await self._server.close()
/usr/local/lib/python3.6/site-packages/pytest_sanic/utils.py:134: in close
await trigger_events(self.after_server_stop, self.loop)
/usr/local/lib/python3.6/site-packages/pytest_sanic/utils.py:25: in trigger_events
result = event(loop)
server.py:84: in finish
loop.run_until_complete(app.aiohttp_session.close())
uvloop/loop.pyx:1445: in uvloop.loop.Loop.run_until_complete
???
uvloop/loop.pyx:1438: in uvloop.loop.Loop.run_until_complete
???
uvloop/loop.pyx:1347: in uvloop.loop.Loop.run_forever
???
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
> ???
E RuntimeError: this event loop is already running.
uvloop/loop.pyx:448: RuntimeError
非常感谢任何帮助或建议。提前致谢