在Django自定义管理命令中测试输入消息文本和答案

时间:2018-01-11 15:24:08

标签: python django unit-testing

我想在自定义管理命令中测试用户输入确认答案。该测试用于向用户显示消息并回答她输入的内容。

命令的代码是:

class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('id', type=int)

    def handle(self, *args, **options):
        try:
            experiment = Experiment.objects.get(pk=options['id'])
        except Experiment.DoesNotExist:
            raise CommandError(
                'Experiment with id "%d" does not exist' % (options['id'])
            )

        answer = input('Are you sure? (Y/n)')
        if answer == 'Y':
            experiment.delete()

accepted answer建议使用模仿,但它处于孤独的环境中。我想测试用户输入以及我可以添加到自定义命令的其他内容。

什么是有效的方法?

1 个答案:

答案 0 :(得分:1)

在搜索了几个来源之后,我找不到一个类似于我的问题的解决方案。所以我混合了一些使用python mock库来获得一个简洁的解决方案。

测试方法(在test_commands.py中):

from unittest.mock import patch
# other imports

@patch('experiments.management.commands.remove_experiment.get_input',
           return_value='Y')
    def test_remove_experiment_displays_prompt_and_user_confirm_removing(
            self, mock_user_input
    ):
        experiment = create_experiment()
        out = StringIO()
        call_command(
            'remove_experiment', experiment.id, stdout=out
        )

        self.assertEqual(mock_user_input.called, True)
        (text,), kwargs = mock_user_input.call_args
        self.assertEqual(text,
            'All versions of experiment "%s" will be destroyed and cannot be '
            'recovered. Are you sure? (Yes/n) ' % experiment.title)
        self.assertFalse(Experiment.objects.exists())

现在,在命令类中,我们在方法中包含python input()(就像问题中提到的accepted answer中所做的那样)。

<强> my_app.management.commands.remove_experiment

def get_input(text):
    return input(text)

class Command(BaseCommand):

    def add_arguments(self, parser):
        parser.add_argument('id', type=int)

    def handle(self, *args, **options):
        try:
            experiment = Experiment.objects.get(pk=options['id'])
        except Experiment.DoesNotExist:
            raise CommandError(
                'Experiment with id "%d" does not exist' % (options['id'])
            )

        answer = get_input('Are you sure? (Y/n)')
        if answer == 'Y':
            experiment.delete()

现在,测试将验证问题文本,在用户输入提示中是正确的,但不会在stdout中显示。此外,return_value='Y'上下文装饰器中的kwarg @patch将模拟用户答案,并且测试通过。