问题
I am trying to test the raising of exceptions by a command implemented with the Click package.
This is my command:
@click.option(
'--bucket_name',
...)
@click.option(
'--group_id',
...)
@click.option(
'--artifact_id',
...)
@click.option(
'--version',
...)
@click.option(
'--artifact_dir',
required=False,
default='downloads/artifacts/',
...)
@click.command()
def download_artifacts(
bucket_name,
group_id, artifact_id, version,
artifact_dir
):
logger.info(
f"bucket_name: {bucket_name}, "
f"group_id: {group_id}, "
f"artifact_id: {artifact_id}, "
f"version: {version}, "
f"artifact_dir: {artifact_dir}, "
)
if not artifact_dir.endswith('/'):
raise ValueError(
"Enter artifact_dir ending with '/' ! artifact_dir: "
f"{artifact_dir}")
...
This is my test code with assertRaises
that doesn't work:
def test_download_artifacts_invalid_dir(
self,
):
runner = CliRunner()
with self.assertRaises(ValueError):
result = runner.invoke(
download_artifacts,
'--bucket_name my_bucket \
--group_id gi \
--artifact_id ai \
--version 1.0.0 \
--artifact_dir artifact_dir'.split(),
input='5')
The assert fails and it gives E AssertionError: ValueError not raised
instead.
I have found this way of testing, which passes, but it doesn't seem very elegant:
def test_download_artifacts_invalid_dir(
self,
):
runner = CliRunner()
result = runner.invoke(
download_artifacts,
'--bucket_name my_bucket \
--group_id gi \
--artifact_id ai \
--version 1.0.0 \
--artifact_dir artifact_dir'.split(),
input='5')
print(f"result.exception: {result.exception}")
assert "Enter artifact_dir ending" in str(result.exception)
回答1:
Two ways to test for exceptions with click.CliRunner()
The first method is hinted out in the DOCS:
Basic Testing
The basic functionality for testing Click applications is the CliRunner which can invoke commands as command line scripts. The CliRunner.invoke() method runs the command line script in isolation and captures the output as both bytes and binary data.
The return value is a [Result] object, which has the captured output data, exit code, and optional exception attached.
result = runner.invoke(throw_value_error)
assert isinstance(result.exception, ValueError)
The second method is to set the catch_exceptions=False
parameter on CliRunner.invoke()
runner.invoke(..., catch_exceptions=False)
Test Code
import click.testing
import pytest
@click.command()
def throw_value_error():
raise ValueError("This is My Message!")
def test_catch_value_error():
"""Read the CliRunner exception report"""
runner = click.testing.CliRunner()
result = runner.invoke(throw_value_error)
assert isinstance(result.exception, ValueError)
assert 'My Message' in str(result.exception)
def test_throw_value_error():
"""Have the CliRunner not catch my exception"""
runner = click.testing.CliRunner()
with pytest.raises(ValueError):
runner.invoke(throw_value_error, catch_exceptions=False)
Test Results
============================= test session starts ==============================
platform linux -- Python 3.7.7, pytest-6.2.1 -- /usr/bin/python
collecting ... collected 2 item
tests/test_api_authz.py::test_catch_value_error PASSED [ 50%]
tests/test_api_authz.py::test_throw_value_error PASSED [100%]
============================== 2 passed in 0.05s ===============================
来源:https://stackoverflow.com/questions/65388531/testing-python-click-command-exceptions