如何在正在运行系统配置接受测试的pytest中管理sys.path

时间:2019-03-11 19:25:51

标签: python ansible pytest

我们有一个测试框架,该框架略微扩展了pytest,并将其包装在许多Ansible中,以便运行系统配置接受测试,以验证我们的基础架构已正确安装和配置,并且运行正常。它通过使用Ansible打包测试,将它们发送到远程主机,然后将其解压缩到virtualenv中以运行测试来实现。到目前为止,大多数人的测试都涉及在远程主机上运行命令以验证它们是否正常工作。 >

我要测试的部分内容是是否已安装某些Python模块并使其正常工作,如果可以,请在进一步的测试中使用它们。但是我有点受阻,因为virtualenv(很正确)隐藏了所有系统安装的Python模块。

到目前为止,我的策略是运行一个subprocess shell命令/小脚本,该脚本将设置所有与virtualenv相关的环境变量,然后使用系统Python运行简短的Python脚本,该脚本将其sys.path腌制,然后将其转储到stdout。

但是我不确定下一步。在测试或固定装置中弄乱sys.path的正确方法是什么?不再需要固定装置后,pytest会恢复它吗? pytest与测试导入的模块有什么关系?测试完成后是否将它们从sys.modules中删除?

1 个答案:

答案 0 :(得分:0)

好吧,我没有得到答案,所以我想出了这个装置来放入conftest.py

@pytest.fixture(scope="module")
def need_system_libraries():
    pycmd = 'unset VIRTUAL_ENV PYTHONPATH; exec {pyexec} -c '\
            '"import sys, pickle; sys.stdout.write(pickle.dumps(sys.path, 0))"'

    pycmd = pycmd.format(pyexec='/usr/bin/python3.7')
    _, stdout, _ = testlib.execute(pycmd)
    system_path = pickle.loads(stdout)
    # Prune any paths from the system_path that already exist in sys.path or     
    # are relative (not absolute) paths.                                         
    newsyspaths = frozenset(system_path) - frozenset(sys.path)
    newsyspaths = frozenset(path for path in newsyspaths
                            if os.path.isabs(path))
    # A set isn't ordered. Put difference back in the same order as the          
    # elements appeared in system_path. (Not needed in Python >= 3.6).           
    newsyspaths = [path for path in system_path if x in newsyspaths]
    # Save a copy of the path so we can restore it.                              
    saved_syspath = sys.path.copy()
    sys.path.extend(newsyspaths)
    # This fixture modifies the environment itself, and so doesn't need to       
    # return a value.                                                            
    yield None
    # The yield will come back when this fixture is no longer needed, so         
    # restore sys.path back to its original value. Do this by copying elements   
    # back into original sys.path in case the identity of sys.path is important  
    # somewhere deep in the bowels of Python.                                    
    sys.path[:] = saved_syspath