2

I want to test user input confirmation answer in a custom management command. The test is for message displayed to user and answer that she enters.

The commands' code is:

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()

This accepted answer suggests to use mocking, but it's in a lonely context. I want to test the user input as well other things that I could add to the custom command.

What would be an efficient approach?

1 Answer 1

3

After searching several sources, I could not find one solution that was similar to my problem. So I mixed some of them to arrive to a neat solution using python mock library.

Test method (in 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())

Now, in command Class we wrap python input() in our method (like did in accepted answer mentioned in the question).

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()

Now, the test will verify the question text, in user input prompt is correct, but will not display it in stdout. Besides, the kwarg return_value='Y' in @patch context decorator will simulate the user answer, and the test passes.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.