如何在Nose中实现导入的“提前返回”?

2 投票
3 回答
740 浏览
提问于 2025-04-17 16:50

我正在为一个大型的Python项目整理大量的单元测试。我们使用nose来发现和执行这些测试。我有一些测试文件在特定条件下根本不应该运行。例如,可能有一个测试模块在Windows上绝对不应该运行(只在Mac和Linux上运行)。

以下是我用过的一些解决方案:

  1. 使用Nose的优秀attrib插件给测试方法或类标记条件。
  2. 在测试方法或类上使用unittest.skipIf()
  3. 使用nose的模式排除,比如跳过名称中包含windows的文件。

我对第1和第2种方法的抱怨是,这些方法迫使我导入模块,这至少浪费时间,如果有依赖于平台的导入,可能还会导致错误。我不喜欢第3种方法,因为我觉得它不够稳健,在阅读测试用例时不容易看出会被跳过。这三种方法似乎都过于依赖测试和测试运行器之间的互动,我希望有一种只在测试中就能解决的方法。

我想在测试模块的顶部做类似下面的事情:

"""This module should not be run on Windows"""
import platform
if platform.system() == 'Windows':
    <stop reading this module.  nothing to see here>

# do the tests.

我该如何告诉Python或Nose停止读取这个模块,但又不报错呢?我想我在寻找一种类似于提前返回的导入方式。

3 个回答

1

你可以在那儿抛出一个ImportError错误,并附上相关信息。调用这个代码的地方可能会因为没有处理这个错误而退出,并显示出这个错误的说明,但如果需要的话,它也可以捕捉到这个ImportError错误。

2

之前有人提议可以让模块在执行时提前返回,但这个想法得到了不少反对票,所以最后没有被加入到语言里。

你可以去看看那个邮件列表的讨论,不过总的来说,大家觉得为了避免模块里大段代码多缩进一层,这个问题不值得添加这个“返回”功能。有些人还说,模块里的代码几乎都应该放在函数和类里面,这样几乎就没有什么模块级别的代码会遇到这个问题。

2

在Nose和unittest这两个测试框架中,SkipTest这个异常是特别处理的——它并不算是失败。因此,下面的代码会停止执行,但不会向unittest的运行器报告任何错误:

import unittest
import platform
if platform.system() == 'Windows':
  raise unittest.case.SkipTest("The rest of this code will not be run on Windows.")

撰写回答