【问题标题】:How to test a function with input() call (unittest)如何使用 input() 调用测试函数 (unittest)
【发布时间】:2021-10-05 22:44:48
【问题描述】:

我想测试以下模块。有数百个类似的模块,每个模块的测试数据存储在input_suffix.txtoutput_suffix.txtsuffix是模块的名称)。

def func(data):
    # do something
    return something

def reader():
    for case_no in range(int(input())):
        n_rows, n_cols = map(int, input().strip('\n').split())
        data = [[int(n) for n in input().strip('\n').split()] for _ in range(n_rows)]
        print(f'Case #{case_no + 1}: {func(data)}')

if __name__ == '__main__':
    reader()

我可以简单地读取要测试的模块的 input_suffix.txtoutput_suffix.txt 文件,并处理输入数据以将数据直接馈送到 func() 并通过将返回值与预期值进行比较来完成工作输出,也可以根据输出数据进行处理。

但是,有数百个类似的模块,它们并不总是共享相同的结构。 input_suffix.txt 的第一行总是表示包含的测试的数量,但在那之后,它会完全不同。有时,每个测试都以包含许多行 (num_rows) 和列 (num_cols) 的行开头,而随后的 num_rows 行是数组的表示形式(就像上面一样)。但是input_suffix.txt 可能根本没有num_rows 或数组表示,或者可能有多个数组或其他类型的数据。同样,func() 的参数也因模块而异。

由于存在差异,我需要修改数百个测试驱动程序,以将正确的预处理数据提供给每个模块的 func() 等效项。为了避免繁重的任务,我需要这些;

  1. 我需要一种方法将数据(取自input_suffix.txt)逐行传递到每个reader()input()(每个模块的每个reader() 已经有足够的数据处理方案,因此,如果我只是逐行传递input_suffix.txt 的内容,它将起作用)。
  2. 我需要一种方法来捕获来自reader() 的打印数据,以将其与来自output_suffix.txt 的预期输出进行比较。

我在io 上有input_suffix.txtoutput_suffix.txt,但我不知道如何解析打印值以将其与o 进行比较。那是我被卡住的地方,但经过一番麻烦,我设法得到了一个工作代码。但我认为这不是这项工作的标准方式。

from contextlib import redirect_stdout
from io import StringIO
from unittest import TestCase
from unittest.mock import MagicMock, patch
from suffix import *

class Tester(TestCase):
    def test(self):
        with open('input_suffix.txt', 'r') as f:
            i = [line.strip('\n') for line in f.readlines()]
        with open('output_suffix.txt', 'r') as f:
            o = [line.strip('\n') for line in f.readlines()]

        m = MagicMock()
        f = StringIO()
        length = len(i)
        with patch('builtins.input', side_effect=i):
            reader()
            for _ in range(length):
                m()
        result  = f.getvalue().split('\n')[:-1]
        for case_no, (actual, expected) in enumerate(zip(result, to)):
            self.assertEqual(actual, expected)
            print(f'Test {case_no + 1} Passed')

您能建议正确的方法吗?任何帮助,将不胜感激。谢谢。

【问题讨论】:

    标签: python unit-testing input mocking


    【解决方案1】:

    您可以使用unittest 库中提供的patch 模拟输入。模拟用户输入的简单代码如下所示。

    实际示例代码:放在路径utils/sample.py

    def take_input():
        response = input("please type a:")
        if response == 'a':
            return "Correct"
        return "Not Correct"
    

    实际测试代码:

    from utils.sample import take_input
    import unittest
    from unittest.mock import patch
    
    
    class TestCache(unittest.TestCase):
        @patch("utils.sample.input", return_value='a')
        def test_take_input(self, mock_input):
            ans = take_input()
            self.assertEqual(ans, 'Correct')
    

    记下patch 的编写方式以及在补丁中调用input 函数以及指定的return_value

    【讨论】:

    • @e1630m 你能解决这个问题吗?
    • 没有。我无法用您的代码替换我当前的代码。输入文件包含随机数量的测试用例,每个测试用例都有随机数量的输入行。我当前的代码将所有内容转储到输入并捕获每条打印的消息,然后将其与预期的输出逐行进行比较。不知道如何用你的实现这一目标。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-08-21
    • 1970-01-01
    • 2011-04-02
    相关资源
    最近更新 更多