【问题标题】:Making pytest wait for user input让 pytest 等待用户输入
【发布时间】:2017-09-04 11:08:49
【问题描述】:

我正在编写一些依赖于用户输入来决定它们是否通过的测试。

我有这个功能:

def viewable(actual_proj):
    print("\nCan you see %s projects named:\n"%len(actual_proj))
    for i in actual_proj:
        print (i+"\n")
    return input("(y/n)? : ")

内:

def is_present(pytestconfig, project_not_present = 0):

    actual_projects = all_projects.copy()
    if (project_not_present!=0):
        del_file = all_ini_files[project_not_present-1]
        os.rename(del_file, del_file +'_tst')
        del actual_projects[project_not_present-1]
    capmanager = pytestconfig.pluginmanager.getplugin('capturemanager')

    subprocess.Popen('./MultiPRM.exe')
    capmanager.suspendcapture(in_=True)

    decision = viewable(actual_projects)
    capmanager.resumecapture()
    if (project_not_present!=0):
        os.rename(del_file+'_tst', del_file)
    if (decision =='y'):
        return True
    else:
        return False

当我运行命令pytest name_of_test_file.py 时,它运行良好,并在每次测试后停止以获取用户输入。但是,我想使用一个为日志文件设置各种变量和标题的文件(称为run_tests.py

# start the report
print("Creating test report: " + os.path.abspath(report_filepath))
rep = open(report_filepath, "w")
rep.write(report_header)
rep.write("Test environment: \n");
rep.write("  Username: " + os.environ['USERNAME'] + "\n")
rep.write("Testing started at: " + get_time() + "\n\n")
rep.close()

# get application version
cmd = exe_under_test + " --help >> " + report_filepath
os.system(cmd)

# start the tests
cmd = "pytest >> " + report_filepath 
os.system(cmd)

# finalise the report
rep = open(report_filepath, "a+")
rep.write("\nTesting completed at: " + get_time() + "\n\n")
rep.close()

当我以这种方式运行它时,它不会停止或运行任何测试。

如果我可以写入日志文件,同时也可以将相同的内容写入终端(包括用户输入),那就太好了。否则,正确调用此函数的方法也将起作用。

【问题讨论】:

  • 单元测试的重点在于它们不需要用户交互...
  • 唯一可以测试这个函数的方法就是这样,可能不正确
  • 您确实需要找到一种方法来模拟用户输入以进行测试。如果您在测试期间依赖用户输入,那么运行您的测试的其他人可能不会与您测试相同的东西。测试应该是确定性的。
  • @PeterKentish 编写您自己的 input() 实现,返回确定性结果。
  • @NilsWerner 你是什么意思?它在 GUI 中测试一些东西,我没有 GUI 测试软件。

标签: python user-input pytest gui-testing


【解决方案1】:

您的测试应该尽可能易于运行,以便轻松执行它们。如果它们将依赖于外部(例如用户)输入和其他一些技巧才能正常运行,那么从长远来看,没有人会执行它们。

如果您是项目中的唯一开发人员,您可能会接受它,但我会说这种方法是不正确的,不被认为是最佳实践

首先,如果您只是在控制台中等待用户输入(这似乎来自您的代码 sn-ps),那么只需模拟 input 内置并设置它的返回值,例如:

app.py

def my_input(prompt=''):
    try:
        return raw_input(prompt)
    except NameError:
        return input(prompt)


def my_great_func():
    choice = my_input('y/n?: ')
    return choice

test.py

import unittest.mock as mock    
import pytest

from app import my_great_func

@pytest.yield_fixture
def fake_input():
    with mock.patch('app.my_input') as m:
        yield m


def test_my_great_func(fake_input):
    fake_input.return_value = 'y'
    assert my_great_func() == 'y'

测试执行:

$ pytest test.py -v
============================= test session starts ==============================
platform linux -- Python 3.5.2, pytest-3.2.1
cachedir: .cache
rootdir: /home/kris/projects/tmp, inifile:
collected 1 item                                                                

test.py::test_my_great_func PASSED

=========================== 1 passed in 0.01 seconds ===========================

其次,努力编写应用程序逻辑和 GUI 松散耦合的代码 - 这样您就可以测试您的逻辑,而无需考虑 GUI(无论是 Web、桌面还是移动应用程序)。

【讨论】:

    【解决方案2】:

    单元测试不应该需要输入,但如果您暂时需要它,这是一种方法。如果您使用标志-s,它将按原样输出,而不是capturing and only displaying on failures。所以如果你使用pytest -s,你可以调用input(),它会在继续之前暂停并等待输入。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-01-26
      • 2016-09-26
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多