PingPing
PingPing

Reputation: 999

Python unittest when use input is inside a loop

I have the following:

def func():
    s = 1
    i = -1
    while i != 0:
        s += i
        i = int(input())
    return s

if __name__ == "__main__":
    result = func()
    print(str(result))

You will see that there is a single call to the function, but the function contains a loop that iterates until the use enters a value of 0.

How do I test this function with unittest library?

Upvotes: 1

Views: 1913

Answers (1)

alexandredias3d
alexandredias3d

Reputation: 391

I am assuming your code is inside a module called mymodule.py. Therefore, you could create a test file name test_mymodule.py to implement your tests. What you want to do is to use the unittest.mock module to have access to the patch() function in order to decorate the builtin input.

What does that mean is that instead of calling the input function to ask for the user input, you are patching it to return the values defined in side_effect. Each call of input will therefore return a value of the list. Notice that you should include 0 as well, otherwise the test will not work.

For each sequence of inputs, you will have to compute manually (or even using your program) to provide the final result for the method assertEqual.

import unittest                                                                                                                                                                               
import unittest.mock                                                                                                                                                                          

from mymodule import func                                                                                                                                                                     

class TestModule(unittest.TestCase):                                                                                                                                                          

    @unittest.mock.patch('builtins.input', side_effect=[1, 2, 3, 0])                                                                                                                          
    def test_func_list1(self, mock):                                                                                                                                                          
        self.assertEqual(func(), 6)                                                                                                                                                           

    @unittest.mock.patch('builtins.input', side_effect=[0])                                                                                                                                   
    def test_func_list2(self, mock):                                                                                                                                                          
        self.assertEqual(func(), 0) 

Each test method should be prefixed with a test_ in its name. The default pattern when using python -m unittest from the CLI looks for test*.py in the current directory (it is the same as running TestLoader.discover(). You can probably change this if you want, but you will have to take a look at the unittest documentation for more details.

Upvotes: 2

Related Questions