Python 使用模拟来处理多个用户输入

sta*_*kjs 3 python unit-testing mocking

这个问题的后续。

我正在 for 循环中接受用户输入,并编写了一个测试用例test_apple_record。在此 for 循环中,它查询一个self.dispatch_requested()可以随机返回 True 或 False 的方法(未显示)。基于这个答案,代码要求用户进行另一个输入——托盘应该发送到哪里。

我正在使用side_effect的参数mock.patch。如何使用模拟自动传递酒店号码作为用户输入?我仍然想继续将数字传递[5, 6, 7]给 for 循环,但现在还想根据响应传递酒店号码self.dispatch_requested()

谢谢

class SomeClass(unittest.TestCase):
    def apple_counter(self):
        apple_record = {}

        for i in range(3):
            apple_tray = input("enter tray number:")
            apple_record[apple_tray]  =  (i+1)*10
            print("i=%d, apple_record=%s"%(i, apple_record))

            if self.dispath_requested():
                number = input("Enter Hotel number to dispatch this tray:")
                update_hotel_record(number, apple_tray)

    def update_hotel_record(self, number, tray):
        self.hotel_record[number] = tray

    def test_apple_record(self):
        with mock.patch('builtins.input', side_effect=[5, 6, 7]):
            self.apple_counter()
Run Code Online (Sandbox Code Playgroud)

idj*_*jaw 5

你实际上希望你的 side_effect 看起来像这样:

m_input.side_effect = [1, 100, 2, 200, 3, 300]
Run Code Online (Sandbox Code Playgroud)

每次调用输入法时,都会返回下一项。因此,每次在循环中,您都会调用 input 两次。

另外,我不知道单元测试的最终结构,但是,看到您在循环中调用的第二个输入周围有一个条件语句,您可能应该围绕该方法设置一个模拟以始终返回 True。

当您遇到要测试代码何时 self.dispath_requested() 返回 false 的情况时,您必须记住第二个输入不会被调用,因此必须相应地重写您的 side_effect 以匹配您的代码的预期行为。

另外,最后,我再次不确定您的代码实际上是什么样子,但是,根据您在同一类下的实际实现和测试代码的情况,我强烈建议不要这样做。尝试类似这样的结构:

创建一个单独的测试类:

class Tests(unittest.TestCase):
    def setUp(self):
        self.s = SomeClass()

    @patch('__builtin__.input')
    def test_apple_record(self, m_input):
        m_input.side_effect = [1, 100, 2, 200, 3, 300]
        self.s.apple_counter()


if __name__ == '__main__':
    unittest.main()
Run Code Online (Sandbox Code Playgroud)

因此,您创建 SomeClass 的实例,然后这实际上会让您更轻松地模拟对象的属性,这将使您的单元测试更容易编写。

您还会注意到我使用了装饰器(@patch)而不是“with”上下文。这是个人喜好,我发现使用装饰器更容易阅读代码。

希望这可以帮助。