如何使用pytest测试get_date函数?

huangapple go评论94阅读模式
英文:

How do I test a get_date function using pytest?

问题

  1. 我有一个名为get_date的函数在一个项目中我被要求使用pytest来测试它

def get_date(string):
try:
date_str = input(string)
date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
return date
except ValueError:
print("Please enter a date in the YYYY-MM-DD format")
return get_date(string)

  1. 我之前有:

def get_date(string):
while True:
try:
date_str = input(string)
date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
return date
except ValueError:
print("Please enter a date in the YYYY-MM-DD format")
raise

def test_get_date(monkeypatch):
inputs = [
"12/06/2023",
"12-06-2023",
"2023/06/12",
"2023/17/87",
"hello",
"2023-06-12",
]
input_values = iter(inputs)
monkeypatch.setattr("builtins.input", lambda _: next(input_values))

  1. # Test first input ("12/06/2023")
  2. with pytest.raises(ValueError):
  3. get_date("Date (YYYY-MM-DD): ")
  4. # Test second input ("12-06-2023")
  5. with pytest.raises(ValueError):
  6. get_date("Date (YYYY-MM-DD): ")
  7. # Test third input ("2023/06/12")
  8. with pytest.raises(ValueError):
  9. get_date("Date (YYYY-MM-DD): ")
  10. # Test fourth input ("hello")
  11. with pytest.raises(ValueError):
  12. get_date("Date (YYYY-MM-DD): ")
  13. # Test fifth output ("2023-06-12")
  14. assert get_date("Date (YYYY-MM-DD): ") == datetime.date(2023, 6, 12)
  1. 这个问题是,当引发ValueError时,程序会崩溃,而不是重新提示用户输入新的内容,这是绝对不能发生的。
  2. 我考虑将该函数更改为一个is_date函数,该函数将返回一个布尔值,但这将涉及更改整个程序,而我不打算这样做,因为一切都运行得很正常。
  3. 此外,这是一个无返回值的函数,因此我无法使用通常的assert方法。我做了一些研究,发现了这种iter方法,但我不确定这是否是最佳方法。
  4. 我真的希望您能帮助我解决这个问题
英文:

I got this function called get_date in a project and I'm requested to test it via pytest.

  1. def get_date(string):
  2. try:
  3. date_str = input(string)
  4. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  5. return date
  6. except ValueError:
  7. print("Please enter a date in the YYYY-MM-DD format")
  8. return get_date(string)

I previously had:

  1. def get_date(string):
  2. while True:
  3. try:
  4. date_str = input(string)
  5. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  6. return date
  7. except ValueError:
  8. print("Please enter a date in the YYYY-MM-DD format")
  9. raise
  1. def test_get_date(monkeypatch):
  2. inputs = [
  3. "12/06/2023",
  4. "12-06-2023",
  5. "2023/06/12",
  6. "2023/17/87",
  7. "hello",
  8. "2023-06-12",
  9. ]
  10. input_values = iter(inputs)
  11. monkeypatch.setattr("builtins.input", lambda _: next(input_values))
  12. # Test first input ("12/06/2023")
  13. with pytest.raises(ValueError):
  14. get_date("Date (YYYY-MM-DD): ")
  15. # Test second input ("12-06-2023")
  16. with pytest.raises(ValueError):
  17. get_date("Date (YYYY-MM-DD): ")
  18. # Test third input ("2023/06/12")
  19. with pytest.raises(ValueError):
  20. get_date("Date (YYYY-MM-DD): ")
  21. # Test fourth input ("hello")
  22. with pytest.raises(ValueError):
  23. get_date("Date (YYYY-MM-DD): ")
  24. # Test fifth output ("2023-06-12")
  25. assert get_date("Date (YYYY-MM-DD): ") == datetime.date(2023, 6, 12)

The issue with this is that when the ValueError is raised the program crashes instead of re-prompting the user for new input, which is something that really can't happen.

I thought of changing the function to a is_date function that would return a bool, but that would involve changing the whole program, which is something I'm not looking for since everything works just fine.

Also, this is a void function and because of it I can't use the usual assert method. I did some research and found this iter method which I'm not sure is the optimal way to do so.

I really hope you can help me solve this problem

答案1

得分: 1

通过添加raise,你会在打印错误消息后重新引发ValueError,从而导致程序崩溃。

因此,如果你希望程序要求用户重新输入数据,需要在get_date函数中删除raise语句。

希望这有所帮助

以下是整个代码:

  1. import datetime
  2. import pytest
  3. def get_date(string):
  4. while True:
  5. try:
  6. date_str = input(string)
  7. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  8. return date
  9. except ValueError:
  10. print("请以YYYY-MM-DD格式输入日期")
  11. def test_get_date(monkeypatch, capfd):
  12. inputs = [
  13. "12/06/2023",
  14. "12-06-2023",
  15. "2023/06/12",
  16. "2023/17/87",
  17. "hello",
  18. "2023-06-12",
  19. ]
  20. input_values = iter(inputs)
  21. monkeypatch.setattr("builtins.input", lambda _: next(input_values))
  22. # 无效输入测试
  23. with pytest.raises(ValueError):
  24. get_date("日期(YYYY-MM-DD):")
  25. captured = capfd.readouterr()
  26. assert "请以YYYY-MM-DD格式输入日期" in captured.out
  27. # 有效输入测试
  28. assert get_date("日期(YYYY-MM-DD):") == date(2023, 6, 12)
  29. capfd.readouterr()允许你捕获本应打印到控制台的输出
  30. 如果你想了解更多请参考[文档][1]
  31. 希望这对你有帮助
  32. [1]: https://docs.pytest.org/en/6.2.x/capture.html
英文:

By adding raise, you re-raise the ValueError after printing the error msg and thus it crashes.

so if you want the program to repromt for the user to re-enter data remove the 'raise' statement in the get-date function.

Hope This Helps

Here is the whole code:

  1. import datetime
  2. import pytest
  3. def get_date(string):
  4. while True:
  5. try:
  6. date_str = input(string)
  7. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  8. return date
  9. except ValueError:
  10. print("Please enter a date in the YYYY-MM-DD format")
  11. def test_get_date(monkeypatch, capfd):
  12. inputs = [
  13. "12/06/2023",
  14. "12-06-2023",
  15. "2023/06/12",
  16. "2023/17/87",
  17. "hello",
  18. "2023-06-12",
  19. ]
  20. input_values = iter(inputs)
  21. monkeypatch.setattr("builtins.input", lambda _: next(input_values))
  22. # invalid inputs test
  23. with pytest.raises(ValueError):
  24. get_date("Date (YYYY-MM-DD): ")
  25. captured = capfd.readouterr()
  26. assert "Please enter a date in the YYYY-MM-DD format" in captured.out
  27. # valid input test
  28. assert get_date("Date (YYYY-MM-DD): ") == date(2023, 6, 12)

capfd.readouterr() allows you to capture the output that would have been printed to the console.
if you wanna more about it doc

Hope This Is Helpful

答案2

得分: 1

以下是已翻译的代码部分:

  1. 这里有一种方法它在 get_input 函数内封装了在输入错误的情况下重新提示用户的操作
  2. def get_input(string):
  3. date_str = input(string)
  4. while True:
  5. try:
  6. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  7. except ValueError:
  8. print("请以 YYYY-MM-DD 格式输入日期")
  9. date_str = input(string)
  10. return date
英文:

Here's an approach that encapsulates the re-prompting the user in case of an input error inside the get_input function.

  1. def get_input(string):
  2. date_str = input(string)
  3. while True:
  4. try:
  5. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  6. except ValueError:
  7. print("Please enter a date in the YYYY-MM-DD format")
  8. date_str = input(string)
  9. return date

答案3

得分: 0

不需要将函数更改为布尔值。只需将日期字符串作为参数传递,并将用户输入移到单独的函数外部。

没有用户输入的get_date函数:

  1. def get_date(date_str):
  2. try:
  3. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  4. return date
  5. except ValueError:
  6. raise

测试:

  1. def test_get_date():
  2. assert get_date("2023-06-12") == datetime.date(2023, 6, 12)
  3. with pytest.raises(ValueError):
  4. get_date("stuff")
  5. with pytest.raises(ValueError):
  6. get_date("2023/06/12")
  7. with pytest.raises(ValueError):
  8. get_date("2023/69/420")

在调用get_date之前,将用户输入添加回代码中,并将其作为date_str参数传递。

英文:

You don't need to change the function to a boolean. Instead just take the date string as an argument and move the user input outside to a separate function.

get_date function without user input:

  1. def get_date(date_str):
  2. try:
  3. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  4. return date
  5. except ValueError:
  6. raise

Testing:

  1. def test_get_date():
  2. assert get_date("2023-06-12") == datetime.date(2023, 6, 12)
  3. with pytest.raises(ValueError):
  4. get_date("stuff")
  5. with pytest.raises(ValueError):
  6. get_date("2023/06/12")
  7. with pytest.raises(ValueError):
  8. get_date("2023/69/420")

Add the user input back into your code before you call get_date and hand it off as as the data_str argument.

答案4

得分: 0

你在原始代码中的思路是正确的 - 你只需要跳过对所有中间情况调用 get_date(),因为 get_date() 的执行将处理那些不良输入,然后提示下一个输入。

然后,在最后,我们可以断言输入列表已耗尽。

  1. #script.py
  2. import datetime
  3. def get_date(string):
  4. # 使用循环而不是递归
  5. while True:
  6. try:
  7. date_str = input(string)
  8. date = datetime.datetime.strptime(date_str, "%Y-%m-%d").date()
  9. except ValueError:
  10. print("请以 YYYY-MM-DD 格式输入日期")
  11. return date
  1. #test_script.py
  2. import pytest
  3. import datetime
  4. from script import get_date
  5. def test_get_date(monkeypatch):
  6. inputs = [
  7. "12/06/2023",
  8. "12-06-2023",
  9. "2023/06/12",
  10. "2023/17/87",
  11. "hello",
  12. "2023-06-12",
  13. ]
  14. input_values = iter(inputs)
  15. monkeypatch.setattr("builtins.input", lambda _: next(input_values))
  16. # 测试所有其他输入是否都被处理,并接受最后一个输入
  17. assert get_date("日期 (YYYY-MM-DD): ") == datetime.date(2023, 6, 12)
  18. with pytest.raises(StopIteration):
  19. _ = input("验证输入列表是否已耗尽")

如果输入列表未耗尽(在“接受”输入后还有值),则 Pytest 会失败,显示:

  1. FAILED test_script.py::test_get_date - Failed: DID NOT RAISE <class 'StopIteration'>
英文:

You have the correct idea in your original code - you just need to skip calling get_date for all the intermediate cases, because the execution of get_date() will handle those bad inputs, and then prompt for the next input.

Then at the end we can assert that the list of inputs was exhausted.

  1. #script.py
  2. import datetime
  3. def get_date(string):
  4. # Use a loop, not recursion
  5. while True:
  6. try:
  7. date_str = input(string)
  8. date = datetime.datetime.strptime(date_str, &quot;%Y-%m-%d&quot;).date()
  9. except ValueError:
  10. print(&quot;Please enter a date in the YYYY-MM-DD format&quot;)
  11. return date
  1. #test_script.py
  2. import pytest
  3. import datetime
  4. from script import get_date
  5. def test_get_date(monkeypatch):
  6. inputs = [
  7. &quot;12/06/2023&quot;,
  8. &quot;12-06-2023&quot;,
  9. &quot;2023/06/12&quot;,
  10. &quot;2023/17/87&quot;,
  11. &quot;hello&quot;,
  12. &quot;2023-06-12&quot;,
  13. ]
  14. input_values = iter(inputs)
  15. monkeypatch.setattr(&quot;builtins.input&quot;, lambda _: next(input_values))
  16. # Test that all other inputs were handled and we accept the last one
  17. assert get_date(&quot;Date (YYYY-MM-DD): &quot;) == datetime.date(2023, 6, 12)
  18. with pytest.raises(StopIteration):
  19. _ = input(&quot;Verify inputs list is exhausted&quot;)

If the inputs list is not exhausted (there are values after an "accepted" input), then Pytest will fail with

  1. FAILED test_script.py::test_get_date - Failed: DID NOT RAISE &lt;class &#39;StopIteration&#39;&gt;

huangapple
  • 本文由 发表于 2023年6月14日 23:28:24
  • 转载请务必保留本文链接:https://go.coder-hub.com/76475217.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定