Pytest 在使用 monkeypatching 进行测试时不循环

Pytest not looping while testing with monkeypatching

我对编程还很陌生,我正在编写一些代码来收集用户的信息并将其添加到电子表格中。这是我要测试的基础:

# let's say this file is called collect.py

def infoBreakdown():
    userData = input("Enter a detail about your info: ")
    # add detail to a new column
    
    assignLetter = input("Want to assign a letter to this detail? (y/n) ")
    
    addLetter = False
    if assignLetter == "y":
        addLetter = True
    while addLetter:
        newLetter = input("Enter a letter to assign to this detail: ")
        # add letter to a single cell within that column
        # each additional letter adds to the same cell

        newLetter = input("Want to assign another letter for this detail?: ")
        if newLetter == "n":
            addLetter = False


def main():
    
    infoBreakdown()

    addInfo = True
    while addInfo:
        newInfo = input("Cool! Want to add more info? (y/n) ")
        if newInfo == "y":
            infoBreakdown()
        else:
            addInfo = False

main()

所以我希望我的测试能够循环添加多个细节和字母,但出于某种原因,它只 运行ning 通过 while 循环一次(我知道,因为我添加了几个标志来制作当然)。更令人困惑的是它只承认 second 运行 而不是第一个。这是我的测试代码:

def input_main(prompt):
    inputRequest = {
        "Enter a detail about your info: ": "Detail #1",
        "Want to assign a letter to this detail? (y/n) ":, "y",
        "Enter a letter to assign to this detail: ":, "A",
        "Want to assign another letter for this detail? (y/n) ":, "y",
        "Enter a letter to assign to this detail: ":, "B",
        "Want to assign another letter for this detail? (y/n) ":, "n",
        "Cool! Want to add more info? (y/n) ": "y",
        "Enter a detail about your info: ": "Detail #2",
        "Want to assign a letter to this detail? (y/n) ":, "n",
        "Cool! Want to add more info? (y/n) ": "n"
}

    return inputRequest[prompt]

def test_main(monkeypatch):

    monkeypatch.setattr('builtins.input', input_main)

    assert collect.main() == None

因此,我希望在电子表格中同时看到“详细信息 #1”(以及带有“AB”的单元格)和“详细信息 #2”,但它只有“详细信息 #2”我运行测试了。这告诉我这可能不是覆盖电子表格的问题,因为它们被输入到不同的列中。

如果我只 运行 它的第一个详细信息,那么我希望在电子表格上看到“详细信息 #1”和一个带有“AB”的单元格,但它只有“详细信息 #1”和一个带有“B”的单元格。

这仅在使用 pytest 时发生 - 如果我手动测试,代码 运行ning 没问题。问题是我要求的输入比这多得多,手动测试会浪费大量时间。对我遗漏了什么有任何见解吗?

首先:感谢您是编程新手并开始编写测试。

您的测试没有按照您期望的方式工作的原因是 dict 没有按照您尝试使用它的方式工作。 dictunique 键到任意值的映射。虽然您的键不能,但您的值可以包含重复项。如果调用 print(len(InputRequest)),您会看到它只包含五个条目:

{'Cool! Want to add more info? (y/n) ': 'n',
 'Enter a detail about your info: ': 'Detail #2',
 'Enter a letter to assign to this detail: ': 'B',
 'Want to assign a letter to this detail? (y/n) ': 'n',
 'Want to assign another letter for this detail? (y/n) ': 'n'}

如果您使用重复键编写字典文字,则重复键只会映射到您分配给它们的最后一个值。这就是为什么您在输出中只看到“Detail #2”的原因。您的测试只在循环中运行一次,因为您的最后一个条目应该完成测试。

我在编写模拟用户输入的测试时所做的,我使用了一个包含在闭包中的 Generator

def make_mock_input(generator):
    def mock_input(*args, **kwargs): # ignore any arguments
        return next(generator) # the state of the generator is stored in the enclosing scope of make_mock_input

    return mock_input


def test_main(monkeypatch):
    def input_generator(user_input):
        yield from user_input

    user_input = ("Detail #1", "y", "A", "y", "B", "n", "y", "Detail #2", "n", "n")
    gen = input_generator(user_input) # create the generator from your input values
    mock_input = make_mock_input(gen)

    monkeypatch.setattr("builtins.input", mock_input)

    assert collect.main() is None # do identity checks with 'is', add checks for output

这样,您的模拟输入函数将在每次调用时 return 序列中的下一个值(忽略所有传递的参数),就像用户输入下一个值一样。

我不得不说,虽然你的测试现在应该可以了,但这不是一个很好的测试。因为测试的想法是如果某些东西没有按预期工作则引发 AssertionError。现在你的测试几乎总是会通过,因为 collect.main() 将总是 return None 如果其中没有引发异常。您应该添加更多断言语句,以编程方式检查输出的有效性。但我相信您会找到大量关于编写好的测试的资源。