如何使用pytest模拟完全重启

ben*_*sop 6 python error-handling microcontroller multiprocessing pytest

如何测试我的程序对于意外关闭的鲁棒性?

我的 python 代码将在意外关闭的微控制器上运行。我想测试意外重新启动的代码的每个部分,并验证它是否正确处理此问题。

尝试:我尝试将代码放入其自己的进程中,然后提前终止它,但这不起作用,因为 MyClass 从命令行调用 7zip,即使进程终止后,该命令仍会继续:

import multiprocessing
import os

def MyClass(multiprocessing.Process):
   ...
   def run():
      os.system("7z a myfile.7z myfile")


process = MyClass()
process.start()
time.sleep(4)
print("terminating early")
process.terminate()
print("done")

Run Code Online (Sandbox Code Playgroud)

我想要的是:

class TestMyClass(unittest.TestCase):
    def test_MyClass_continuity(self):
        myclass = MyClass().start()
        myclass.kill_everything()
        myclass = MyClass().start()
        self.assert_everything_worked_as_expected()

Run Code Online (Sandbox Code Playgroud)

是否有捷径可寻?如果没有,您如何设计可以在任何点终止的健壮代码(例如测试状态机)?

类似的问题(截至 21 年 10 月 26 日尚未回答):Simizing异常终止 in pytest

多谢!

nox*_*fox 2

您的逻辑启动一个包装在MyClass对象内的进程,该对象本身通过调用生成一个新进程os.system

当您终止MyClass进程时,您会终止父进程,但会让该7zip进程作为孤立进程运行。

此外,该方法还向子进程process.terminate发送信号。SIGTERM子进程可以拦截所述信号并在终止之前执行一些清理例程。如果您想模拟没有机会清理的情况(断电),这并不理想。您很可能想发送一个SIGKILL信号(在 Linux 上)。

要杀死父进程和子进程,需要处理整个进程组。

import os
import time
import signal
import multiprocessing


class MyClass(multiprocessing.Process):
    def run(self):
        # Ping localhost for a limited amount of time
        os.system("ping -c 12 127.0.0.1")


process = MyClass()
process.start()

time.sleep(4)

print("terminating early")

# Send SIGKILL signal to the entire process group
group_id = os.getpgid(process.pid)
os.killpg(group_id, signal.SIGKILL)

print("done")
Run Code Online (Sandbox Code Playgroud)

以上仅适用于 Unix 操作系统,不适用于 Windows 操作系统。

对于 Windows,您需要使用psutil模块。

import os
import time
import multiprocessing

import psutil


class MyClass(multiprocessing.Process):
    def run(self):
        # Ping localhost for a limited amount of time
        os.system("ping -c 12 127.0.0.1")


def kill_process_group(pid):
    process = psutil.Process(pid)
    children = process.children(recursive=True)

    # First terminate all children
    for child in children:
        child.kill()
    psutil.wait_procs(children)

    # Then terminate the parent process
    process.kill()
    process.wait()


process = MyClass()
process.start()

time.sleep(4)

print("terminating early")

kill_process_group(process.pid)

print("done")
Run Code Online (Sandbox Code Playgroud)