【问题标题】:Testing User Input - Python测试用户输入 - Python
【发布时间】:2019-10-13 20:47:27
【问题描述】:

我无法在 Python 中测试我的代码输入。我尝试了几个解决方案,但我缺少一些东西,所以如果你能给我一些提示,我将不胜感激。

首先是我要测试的主代码文件中的 sn-p:

if __name__ == '__main__':

    n = int(input())
    m = int(input())

    grid = []

    for _ in range(n):
        grid.append(list(map(str, input().rstrip().split())))

    calculate(grid)

当我运行我的代码时,我输入“n”,然后输入“m”,然后根据用户输入创建一个网格(每一行在一个新行上......),并执行一个函数来计算一些关于网格和函数返回结果。这一切都很好,但现在我需要为它创建几个测试用例(根据预期输出测试不同的输入)。

首先,我尝试了这个:(在单独的 .py 文件上)

from unittest import mock
from unittest import TestCase
import main_file

class DictCreateTests(TestCase):
    @mock.patch('main_file.input', create=True)
    def testdictCreateSimple(self, mocked_input):
        mocked_input.side_effect = ['2', '2', 'R G B\nR G B'] #this is the input I need for my color grid
        self.assertEqual(calculate(grid), 2)

if __name__ == '__main__':
    unittest.main()

然后我研究了更多选项并尝试了这个选项,这让我最接近:

import unittest
import os

class Test1(unittest.TestCase):

    def test_case1(self):
        input = "2\n2\nR G B\nR G B"
        expected_output = '2'
        with os.popen("echo " + input + "' | python main_file.py") as o:
            output = o.read()
        output = output.strip() # Remove leading spaces and LFs
        self.assertEqual(output, expected_output)

if __name__ == '__main__':
    unittest.main()

不幸的是,即使它通过了测试,我发现当它与预期输出进行比较时,它总是接受输入的第一个字母/数字作为结果。所以,我认为这与我需要输入的多个值有关。我尝试在不同的输入(输入 1 + 输入 2+ 输入 3)上将它们分开,但它仍然不起作用。

如果有人能给我一些如何操作的提示,我将不胜感激!提前谢谢!

【问题讨论】:

标签: python testing input


【解决方案1】:

我建议重构代码,以便您可以测试一个功能:

def create_grid_and_calculate(n, m):
    grid = []

    for _ in range(n):
        grid.append(list(map(str, input().rstrip().split())))

    return calculate(grid)


if __name__ == '__main__':

    n = int(input())
    m = int(input())

    create_grid_and_calculate(n, m)

然后

import unittest
import os
from main_file import create_grid_and_calculate

class Test1(unittest.TestCase):

    def test_case1(self):
        expected_output = '2'
        self.assertEqual(create_grid_and_calculate(2, 2), expected_output)
        self.assertEqual(create_grid_and_calculate(int("R G B"), int("R G B")), expected_output)

if __name__ == '__main__':
    unittest.main()

您还可以用命令行上传递的参数替换您的输入,使用专用模块(例如argparse 是标准模块)解析,以便更好地控制您的输入。

import argparse

def create_grid_and_calculate(n, m):
    ...


def main(argv: list = None):
    parser = argparse.ArgumentParser(description="My script...")
    parser.add_argument(
        "-m",
        dest="m",
        action="store",
        type=int,
        help="parameter m",
    )
    parser.add_argument(
        "-n",
        dest="n",
        action="store",
        type=int,
        help="parameter n",
    )
    args = parser.parse_args(argv or [])

    create_grid_and_calculate(args.n, args.m)

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv[1:]))

所以你也可以用不同的输入(int、strings...)来测试主函数。

最后,pytest 是一个建立在unittest 之上的出色的单一测试框架,也许你可以看看。


编辑: 要定义网格,您不需要输入尺寸(n 和 m),也不需要单独输入每一行。为行选择一个分隔符(此处为逗号),为列选择另一个分隔符(此处为空格),您会得到:

import argparse

def main(argv: list = None):
    parser = argparse.ArgumentParser(description="My script...")
    parser.add_argument(
        "-g",
        "--grid",
        dest="grid",
        action="store",
        type=str,
        help="The grid, defined as 'x11 x12 ... x1n, x21 x22 ... x2n, ...'",
    )
    args = parser.parse_args(argv or [])

    # first we split on comma, then on space
    grid = [x.split() for x in args.grid.split(',')]
    print(grid)
    calculate(grid)

if __name__ == '__main__':
    import sys
    sys.exit(main(sys.argv[1:]))

然后你就这样运行它:main_file.py -g '1 2 3, 4 5 6, 7 8 9'

[['1', '2', '3'], ['4', '5', '6'], ['7', '8', '9']]

要获取 int 列表,请使用:

grid = [[int(val) for val in row.split()] for row in args.grid.split(',')]

或许更清楚:

grid = []
for row in args.grid.split(','):
    grid.append([])
    for val in row.split():
        grid[-1].append(int(val))

【讨论】:

  • 非常感谢您的回答!我非常喜欢对主代码的重构,但是关于测试代码我还有一个小问题——在self.assertEqual(create_grid_and_calculate(int("RGB"), int("RGB")), expected_output)中,你正在尝试将用户根据参数 n 和 m(行和列)输入函数的内容作为参数。我认为这可能是测试用例循环运行的原因。我明白了你的逻辑——我只是不知道如何包含这个“第二个输入”——你在网格中放置“R G B”的那个,所以它最终可以比较它们。
猜你喜欢
  • 2014-06-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2013-06-26
  • 1970-01-01
  • 2019-02-28
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多