如何在方法内部调用其他方法时模拟用户输入——以getpass密码输入场景为例
Hey there! Let's break down how to properly simulate that manual password input when testing your ConfigedParser class, since your initial approach didn't work (and I'll explain why), plus show you a more precise alternative to mocking the entire pass_arg method.
The Problem Context
You're trying to test the ConfigedParser constructor, which calls pass_arg—a method that uses getpass() to prompt for a password when the -p argument isn't provided. Your first attempt to patch builtins.input didn't resolve the issue, so you ended up mocking the whole pass_arg method to get the test to pass.
Why Your Initial Patch Failed
Here's the key detail you might have missed: pass_arg uses getpass(), not the regular input() function. The getpass.getpass function is a separate utility (it even hides the input as you type), so patching builtins.input doesn't affect its behavior at all. That's why your first test still triggered the password prompt.
The Precise Fix: Mock getpass.getpass Instead
You don't need to mock the entire pass_arg method—you can directly mock the getpass function to return your test password. This way, you're actually validating the logic inside pass_arg (like checking if -p was provided) instead of skipping it entirely.
Here's how to implement this:
import unittest from unittest.mock import patch import getpass from your_module import ConfigedParser # Replace with your actual module name class TestConfigedParser(unittest.TestCase): @patch('getpass.getpass', return_value='my_test_pass') def test_no_password_provided(self, mock_getpass): """Test that getpass is called when -p argument is missing""" # Reset sys.argv to avoid interference from test runner arguments import sys sys.argv = ['test_program'] # Simulate running the script without CLI args parser = ConfigedParser() # Verify the password was set to our mock value self.assertEqual(parser.get_args()['p'], 'my_test_pass') # Ensure getpass was called exactly once mock_getpass.assert_called_once()
A Note on Your Current Mock Approach
Mocking the entire pass_arg method does let the test run without prompting for input, but it skips testing the actual logic of pass_arg. If someone later changes how pass_arg checks for the password argument or handles the input, your test won't catch those regressions. Using the targeted getpass mock is better because it validates the real behavior of your code.
One More Tip: Handle sys.argv for Argparse Tests
When testing code that uses argparse, always reset sys.argv at the start of your test. The parse_args() method reads from sys.argv by default, so any arguments passed to your test runner (like -v for verbose mode) will interfere with your test's argument parsing. Resetting it to a clean state ensures your test runs with the exact arguments you want.
内容的提问来源于stack exchange,提问作者Damian Kapłon

