0

Substituting the built-in input function's value with a string is often used to test whether a method has the expected response to that input. A tool like monkeypatch would be used to do this, then we'd assert that calling the method returns the expected value.

Even when you call another method inside the method, if the second one has a predictable return value, you can use a similar approach.

Now, what if that method's expected behaviour is to call a method which also asks for input? The aim is to make sure that the program reached that second input prompt (confirming the first input had the expected result). Is there a way to assert this alone?

Example:

class TwoInputs:

    def method_a(self):
        self.action = input("Enter something: ")
        if self.action == "jump":
            self.method_b()
            self.method_a()
        elif self.action == "exit":
            quit()

    def method_b(self):
        while True:
            self.action = input("Enter some other thing: ")
            if self.action == "1":
                print("Hello world.")
                break
            else:
                print("Invalid input.")

In the above context, how would you test that method_a successfully calls method_b, and just end the test there? If I were to monkeypatch input by changing it to "jump", then simply call method_a, that same input would be picked up as invalid in method_b, which then would loop continuously.

1 Answers1

0

To check if method_b has been called, you have to mock it. Also you have to mock input, as you mentioned, and make sure it returns values that will lead to the program to ended, and not to a recursion:

@mock.patch("two_inputs.TwoInputs.method_b")
@mock.patch("two_inputs.input")
@mock.patch("two_inputs.quit")
def test_that_a_calls_b(mock_quit, mock_input, mocked_method_b):
    # consecutive call results - second call is from inside `method_a`
    mock_input.side_effect = ["jump", "exit"]
    two_inputs = TwoInputs()
    two_inputs.method_a()
    mocked_method_b.assert_called_once()

This assumes that your class lives in two_inputs.py at the project root.

For your case, I also added mocking the system function quit (otherwise the test would just quit), though I guess you won't call this in your real code.

MrBean Bremen
  • 14,916
  • 3
  • 26
  • 46