2

I have this function definition :

def interactive_mode():
    parking_query = Query()

    while(True):
        query = input()
        if query == 'exit':
            return -1
        else:
            parking_query.process(query)

I need to test this function using pytest, how can mock the input() in my tests file when it is inside an infinite loop?

Also, after mocking the input I need to capture the output to each input from stdout which could be done using capsys in pytest.

Things that I have tried doing :

1.

monkeypatch.setattr('sys.stdin', io.StringIO(query))

This gives and EOF error, doesn't work!

2.

from unittest.mock import Mock

mock_stdin = Mock()
mock_stdin.readline = Mock(io.StringIO(query))

monkeypatch.setattr('sys.stdin', io.StringIO(query))

Get's stuck infinitely when I run pytest

My test function:

def test_interactive_mode(capsys, monkeypatch):
    '''
        Tests the interactive_mode() method by mocking
        stdin using monkeypatch and reading stdout using capsys
    '''
    testcases = [
        {
            'input':  [
                        'input query'
                      ],
            'output': [
                        'expected output response to query'
                      ] 
        }
    ]

    for case in testcases:
        for i, query in enumerate(case['input']):
            with mock.patch.object(builtins, 'input', lambda : query):
                # mock_stdin = Mock()
                # mock_stdin.readline = Mock(io.StringIO(query))

                # monkeypatch.setattr('sys.stdin', io.StringIO(query))

                return_value = interactive_mode()

                if return_value == -1:
                    break

                captured = capsys.readouterr()

                assert captured.out == case['output'][i] + '\n'

1 Answer 1

2

Found a hacky way to solve the problem, serves the purpose but wouldn't suggest as the perfect solution!

def test_interactive_mode(capsys, monkeypatch):
    '''
        Tests the interactive_mode() method by mocking
        stdin using monkeypatch and reading stdout using capsys
    '''
    testcases = [
        {
            'input':  [
                        'input query'
                      ],
            'output': [
                        'expected output response to query'
                      ] 
        }
    ]

    for case in testcases:
        for i, query in enumerate(case['input']):
            with mock.patch('builtins.input', side_effect=[query, 'exit']):
                return_value = interactive_mode()

                if return_value == -1:
                    break

                captured = capsys.readouterr()

                assert captured.out == case['output'][i] + '\n'
Sign up to request clarification or add additional context in comments.

3 Comments

You probably want to use parametrization instead of manually handling the test cases, but apart from that, it looks like a clever solution to me!
Hi! Could you elaborate on the parametrization method, I don't quite understand what that means, thanks!
I mean pytest.mark.parametrize, so in your test, you can define testcases outside and use the decorator to run the test for each set of parameters.

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.