模拟标准输入-python 3中的多行

模拟标准输入-python 3中的多行,python,unit-testing,python-3.x,lambda,patch,Python,Unit Testing,Python 3.x,Lambda,Patch,我是python新手,一直在使用python 3进行学习。我正在使用python的单元测试框架来测试我的代码 问题:- 我需要进行单元测试的函数以以下方式获取输入:- def compare(): a, b, c = input().strip().split(' ') d, e, f = input().strip().split(' ') # other code here 我使用以下测试用例模拟输入:- class TestCompare(unittest.TestCa

我是python新手,一直在使用python 3进行学习。我正在使用python的单元测试框架来测试我的代码

问题:-

我需要进行单元测试的函数以以下方式获取输入:-

def compare():
   a, b, c = input().strip().split(' ')
   d, e, f = input().strip().split(' ')
   # other code here
我使用以下测试用例模拟输入:-

class TestCompare(unittest.TestCase):

   @patch("builtins.input", lambda: "1 2 3")
   @patch("builtins.input", lambda: "4 5 6")
   def test_compare(self):
      self.assertEqual(compare(), "1 1")
我面临的问题是,当测试用例运行时,变量三元组a、b、c和d、e、f具有相同的值-1、2、3

我一直试图找到一种方法来注入第二组输入来运行我的测试,但没有成功

非常感谢您在上述方面提供的任何帮助


解决方案环境:-Python3

您不能像这样修补它两次。您必须使用在后续调用中返回不同值的对象对其进行一次修补。下面是一个例子:

fake_input = iter(['1 2 3', '4 5 6']).__next__

@patch("builtins.input", fake_input)
def test_compare(self):
    ...

你不能像那样打两次补丁。您必须使用在后续调用中返回不同值的对象对其进行一次修补。下面是一个例子:

fake_input = iter(['1 2 3', '4 5 6']).__next__

@patch("builtins.input", fake_input)
def test_compare(self):
    ...

补丁修饰符将确保补丁函数始终返回该值,如果后续调用必须不同,则您的模拟对象必须有方法模拟该值。这最终要复杂得多

但是,您可以做的是降低一步并修补底层,这是标准的输入/输出层。其他测试框架所采用的一种常见策略是直接处理
sys.stdin
sys.stdout
对象。考虑这一点:

import unittest
from unittest.mock import patch

from io import StringIO

def compare():
    a, b, c = input().strip().split(' ')
    d, e, f = input().strip().split(' ')

    return '%s %s' % (a, d)

class TestCompareSysStdin(unittest.TestCase):

    @patch("sys.stdin", StringIO("1 2 3\n4 5 6"))
    def test_compare(self):
        self.assertEqual(compare(), "1 4")
执行

$ python -m unittest foo
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

当然,这在较低的级别上工作,因此在后续调用中使用迭代器返回不同值的选项可能更合适。

补丁装饰器将确保补丁函数始终返回该值,如果后续调用必须不同,则您的模拟对象必须具有模拟该值的方法。这最终要复杂得多

但是,您可以做的是降低一步并修补底层,这是标准的输入/输出层。其他测试框架所采用的一种常见策略是直接处理
sys.stdin
sys.stdout
对象。考虑这一点:

import unittest
from unittest.mock import patch

from io import StringIO

def compare():
    a, b, c = input().strip().split(' ')
    d, e, f = input().strip().split(' ')

    return '%s %s' % (a, d)

class TestCompareSysStdin(unittest.TestCase):

    @patch("sys.stdin", StringIO("1 2 3\n4 5 6"))
    def test_compare(self):
        self.assertEqual(compare(), "1 4")
执行

$ python -m unittest foo
.
----------------------------------------------------------------------
Ran 1 test in 0.000s

OK

当然,这在较低的级别上起作用,因此在后续调用中使用迭代器返回不同值的选项可能更合适。

您不能像这样对函数进行两次修补。当您希望模拟同一个函数,并让它在每次调用时返回不同的值时,您应该使用

副作用
获取一个值列表,其中列表中的每个值都是每次在代码中调用该函数时的返回值:

class TestCompare(unittest.TestCase):

    @patch("builtins.input", side_effect=["1 2 3", "4 5 6"])
    def test_compare(self, mock_input):
        self.assertEqual(compare(), "1 1") 

你不能像那样两次修补你的函数。当您希望模拟同一个函数,并让它在每次调用时返回不同的值时,您应该使用

副作用
获取一个值列表,其中列表中的每个值都是每次在代码中调用该函数时的返回值:

class TestCompare(unittest.TestCase):

    @patch("builtins.input", side_effect=["1 2 3", "4 5 6"])
    def test_compare(self, mock_input):
        self.assertEqual(compare(), "1 1") 

nit-您的
def
nit有一个选项卡问题-您的
def
有一个选项卡问题,我注意到您接受了我的答案,然后又接受了另一个答案(这从我的答案中删除了接受,这很好,只是想确保您知道)。你知道每个问题只能接受一个答案吗。。对此我很抱歉。实际上你发的和wim发的都有效。我会记住,只有一个答案是可以接受的。谢谢你指出这一点。我注意到你接受了我的答案,然后又接受了另一个(这从我的答案中删除了接受,这很好,只是想确保你知道)。你知道每个问题只能接受一个答案吗。。对此我很抱歉。实际上你发的和wim发的都有效。我会记住,只有一个答案是可以接受的。谢谢你指出这一点。