0

I need to test a function that handles inputs. I'm a newbie in all about unittests and mocks so I just basically followed this answer https://stackoverflow.com/a/21047132/6531256 that it looks very similar to my case. Well, the problem is that when i run the test it seems to start but just stay there and nothing happens. I need to quit with ctrl-c to stop it, then I get a traceback that not helps very much(at least for me).

Here is the test code:

import unittest
import unittest.mock
from unittest.mock import patch
from work1 import User

class TestWork1(unittest.TestCase, User):

    @patch('builtins.input', return_value= "36")
    def test_userNum(self,return_value):

        self.assertEqual(self.userNum(), "Invalid number. Put a 4-digit number:")


if __name__ == "__main__":
    unittest.main()

Here the function trying to test:

class User():

    def userNum(self):

        self.user_num = int(input("Put a 4-digit number"))
        while len(str(self.user_num)) != 4:
            self.user_num = int(input("Invalid number. Put a 4-digit number:"))

Here is an example of a Traceback (always are a little diferent):

Traceback (most recent call last):
  File "/usr/lib/python3.5/runpy.py", line 184, in _run_module_as_main
    "__main__", mod_spec)
  File "/usr/lib/python3.5/runpy.py", line 85, in _run_code
    exec(code, run_globals)
  File "/usr/lib/python3.5/unittest/__main__.py", line 18, in <module>
    main(module=None)
  File "/usr/lib/python3.5/unittest/main.py", line 94, in __init__
    self.runTests()
  File "/usr/lib/python3.5/unittest/main.py", line 255, in runTests
    self.result = testRunner.run(self.test)
  File "/usr/lib/python3.5/unittest/runner.py", line 176, in run
    test(result)
  File "/usr/lib/python3.5/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "/usr/lib/python3.5/unittest/suite.py", line 122, in run
    test(result)
  File "/usr/lib/python3.5/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "/usr/lib/python3.5/unittest/suite.py", line 122, in run
    test(result)
  File "/usr/lib/python3.5/unittest/suite.py", line 84, in __call__
    return self.run(*args, **kwds)
  File "/usr/lib/python3.5/unittest/suite.py", line 122, in run
    test(result)
  File "/usr/lib/python3.5/unittest/case.py", line 648, in __call__
    return self.run(*args, **kwds)
  File "/usr/lib/python3.5/unittest/case.py", line 600, in run
    testMethod()
  File "/usr/lib/python3.5/unittest/mock.py", line 1157, in patched
    return func(*args, **keywargs)
  File "/home/cristian/venvs/EB/test_work1.py", line 15, in test_userNum
    self.assertEqual(self.userNum(), "Invalid number. Put a 4-digit number:")
  File "/home/cristian/venvs/EB/work1.py", line 15, in userNum
    self.user_num = int(input("Invalid number. Put a 4-digit number:""))
  File "/usr/lib/python3.5/unittest/mock.py", line 916, in __call__
    _mock_self._mock_check_sig(*args, **kwargs)
KeyboardInterrupt

What can be wrong?

Cristianjs19
  • 765
  • 1
  • 9
  • 15

1 Answers1

1

Your code has several problems:

  1. Your loop runs infinitely because you patch builtin.input to always return "36". This will not allow the loop to exit - when you run the code, it seems that nothing happens, but the code is just looping. To see what happens, you can put print() statements at the interesting places. To fix it, you either have to define return_value such that it returns a 4-digit number, or you have to define side_effect to be a list like ["36", "1234"] such that consecutive calls to builtin.input return different values. The latter option is shown in the code example below.
  2. Your assertion compares the result of self.userNum() against a string. But, self.userNum() does not return anything. From your test code it seems you want to test that buitin.input was called with the respective argument string. How this can be done is shown in the code below - as one possible solution, where in fact the whole sequence of calls to builtin.input is checked. This is only for demonstration, not to imply that it should be done this way.

Possible solution:

import unittest
import unittest.mock
from unittest.mock import patch, call

class User():
    def userNum(self):
        self.user_num = int(input("Put a 4-digit number"))
        while len(str(self.user_num)) != 4:
            self.user_num = int(input("Invalid number. Put a 4-digit number:"))

class TestWork1(unittest.TestCase, User):
    @patch('builtins.input', side_effect=["36", "1234"])
    def test_userNum(self, input_mock):
        expected = [
            call('Put a 4-digit number'),
            call('Invalid number. Put a 4-digit number:')]
        self.userNum()
        self.assertEqual(input_mock.mock_calls, expected)

if __name__ == "__main__":
    unittest.main()
Dirk Herrmann
  • 5,550
  • 1
  • 21
  • 47
  • Sir your answer is right. I was stuck there and had to solve it to finish the task. Find this by myself sure it will have been hard for me.. I would like to sincerely thank Mr. Dirk. – Cristianjs19 May 22 '19 at 00:28