pytest-xdist 一些不为人知的细节

最近在整 GPT 这块的接口测试,收到了来自开发同学各式各样的需求。随着代码的日益庞大和测试集的日益增长,逐渐面临了测试效率低下的问题,需要使用并发的形式予以解决,具体的实现就不在这里细聊,只说在使用过程中碰到的一些问题。

问题1:Different tests were collected between gw0 and gw1

这个问题谷歌一下后在 StackOverflow 找到了问题产生的原因。

Each worker performs a standard collection and sends the collected test ids (in order) back to the master node. The master node ensures every worker collected the same number of tests and in the same order because the scheduler will from that point on send just the test indexes (not the entire node id) to each worker to tell them which test to execute. That's why the collection must be the same across all workers.

说人话,就是当使用 xdist 进行并发测试时,有多少并发就会收集多少次测试用例,如果每个并发里收集到的用例不一致,就会报这个错。

由于收集测试集的逻辑是每次都会从上万条测试集中随机抽取N个进行测试,所以造成了这个问题,我心想那我换成单例模式吧,这样应该能过,结果换成单例之后依旧报同样的问题,并且相关的信息也无法打印出来。

后来再仔细读了 xdist 的文档后大致明白,因为使用的是多进程的逻辑,单例模式并不会跨进程单例,只能在进程内单例,所以这个方法是行不通的,同样的包括环境变量等等方案也都行不通。

最后只能改变取数逻辑,在测试开始前将数据取出,放到一个临时的 JSON 文件中,在测试时都去读取这个文件,测试结束后删除文件,最终解决了这个问题。

问题2:钩子函数怎么有些能触发有些不能触发?

解决了上面的问题后,并发顺利开始执行了,但是当测试完成后又发现了一些问题,我设置的钩子函数 pytest_runtest_makereport 没有触发,但是同样是钩子函数 pytest_runtest_protocolpytest_terminal_summary 却都正常触发了。

而以上这些钩子函数在未进行并发测试时均可正常触发。

大概代码如下

def pytest_terminal_summary(terminalreporter, exitstatus, config):
    print('pytest_terminal_summary')
    print(json.dumps(result_count))

def pytest_runtest_makereport(item, call):
    print('pytest_runtest_makereport')
    result_count['count'] += 1

测试结果如下

pytest_terminal_summary
{"count": 0}

我表示,离了个大谱。

对于一般的使用来说,这些影响不大,但是因为开发同学的需求,我需要在 pytest_runtest_makereport 中进行一些数据统计,如果不触发的话会在测试结束后增加很多的人工统计工作,效率很低。

讲道理,本来就是为了提效,结果有一个需求被卡住了,又会导致效率很低,绝对不能忍。

后来根据这个「一些触发一些没触发」的思路,谷歌了半天没有得到任何有效的信息,我开始了自我怀疑——难道我是天选之人?不可能!绝对不可能。根据我在世为人这么多年的经验,这种好事轮也轮不到我,肯定是哪里出了问题。

于是我又回到了多进程的思路里,难道跟之前的问题一样,这个 result_count 其实不是我想的那个,它在不同进程都有分身。于是我拿出了与问题一同样的解题思路——一个临时的 JSON 文件,用于代替 result_count 的功能,最后文件中果然很正常的写入了内容。

至此破案了。

总结

多进程是个好东西,但是因为平时基本是多线程在玩,所以对它的一些特性不够敏感,导致花费了比较多时间去了解和解决。

同时对此前的代码结构也进行了比较多的修改,最终才适配多进程的要求。我看着多出来这么多文件IO,吃饭都不香了,接下来就要想办法不用文件的形式去共享这些数据。

后记

忙完手头的工作后,立刻马不停蹄的查了一下该如何在 pytest-xdist 中进行进程间通信,发现官方的例子也是使用文件来进行通信,那只能先这样了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容