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
没有按照您尝试使用它的方式工作。 dict
是 unique 键到任意值的映射。虽然您的键不能,但您的值可以包含重复项。如果调用 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
如果其中没有引发异常。您应该添加更多断言语句,以编程方式检查输出的有效性。但我相信您会找到大量关于编写好的测试的资源。
我对编程还很陌生,我正在编写一些代码来收集用户的信息并将其添加到电子表格中。这是我要测试的基础:
# 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
没有按照您尝试使用它的方式工作。 dict
是 unique 键到任意值的映射。虽然您的键不能,但您的值可以包含重复项。如果调用 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
如果其中没有引发异常。您应该添加更多断言语句,以编程方式检查输出的有效性。但我相信您会找到大量关于编写好的测试的资源。