【问题标题】:How to test a statement for KeyboardInterrupt in PyTest?如何在 PyTest 中测试 KeyboardInterrupt 的语句?
【发布时间】:2022-10-30 19:52:05
【问题描述】:

假设我的主文件中有一个函数,如下所示:

# main.py
import time

def little_sleep(num):
   time.sleep(float(f'0.{i}'))

def wait():
    i = 0
    while True:
        try:
            little_sleep(i)
        except KeyboardInterrupt:
            print("Uh Oh!! You really got me there, I guess I'll just have to exit then...")
            break
    return

我必须对这个模块和其中的每一个函数进行 PyTest。 我的问题是,我将如何使用 KeyboardInterrupt 进行测试,而其他测试不会发生任何事情并且内部功能不会受到影响?

# test_main.py
import main
from multiprocessing import Process
import os, time, signal

def test_wait(capfd):
    process = Process(target= main.wait)
    process.start()
    time.sleep(1)
    
    # I tried this but it is sometimes killing the little_sleep() function 
    # and hence the signal is not getting captured by the except 
    os.kill(process.pid, signal.CTRL_C_EVENT)

    # I also tried this but it is directly killing the process without any output and hence is not feasible
    process.kill()

    captured = capfd.readouterr()
    assert captured.out == "Uh Oh!! You really got me there, I guess I'll just have to exit then...\n"

>> pytest test_main.py

collected 1 item
test_main.py F 

=============================== FAILURES ===================================
_______________________________ test_wait __________________________________

capfd = <_pytest.capture.CaptureFixture object at 0x000001F89F7BD400>

    def test_wait(capfd):
        ...
        captured = capfd.readouterr()
>       assert captured.out == "Uh Oh!! You really got me there, I guess I'll just have to exit then...\n"
E       AssertionError: assert '' == 'Uh Oh!! You ...xit then...\n'
E         - Uh Oh!! You really got me there, I guess I'll just have to exit then...

test_main.py:19: AssertionError

有什么解决方法吗?

【问题讨论】:

    标签: python exception process pytest keyboardinterrupt


    【解决方案1】:

    您可以使用MagicMock 及其side_effect 属性模拟little_sleep,以便引发KeyboardInterrupt 异常:

    import unittest.mock
    import main
    
    def test_wait(capfd):
        unittest.mock.MagicMock('main.little_sleep', side_effect=KeyboardInterrupt)
        main.wait()
    
        captured = capfd.readouterr()
        assert captured.out == "Uh Oh!! You really got me there, I guess I'll just have to exit then...
    "
    

    (未经测试的例子)

    【讨论】:

      【解决方案2】:

      您可以自己安装信号处理程序并管理 KeyboardInterrupt。

      import signal
      
      # Save the default handler and optionally restore it at the end of the test.
      default_handler = signal.getsignal(signal.SIGINT)
      
      def handler(signum, frame):
          print('Signal handler called with signal', signum)
         
      signal.signal(signal.SIGINT, handler)
      

      https://docs.python.org/3/library/signal.html

      另外,我会为尝试提供更广泛的范围......除了让它更健壮和高效:

      try:
          while True:
              little_sleep(i)
      except KeyboardInterrupt:
              print("Uh Oh!! You really got me there, I guess I'll just have to exit then...")
      

      它可以在不处理信号的情况下解决您的问题。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2020-07-31
        • 2021-05-19
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-03-01
        • 2022-12-15
        • 1970-01-01
        相关资源
        最近更新 更多