【问题标题】:Run all tests from subdirectories in Python从 Python 中的子目录运行所有测试
【发布时间】:2017-06-22 19:51:31
【问题描述】:

我想尽办法让我的所有单元测试都在 Python 中运行。我已经搜索了大约 30 个不同的帖子和单元测试文档,但仍然无法弄清楚。

首先我有两个测试类,我可以分别运行它们并且所有测试都通过:

文件:unittest.subfolder1.TestObject1.py

class TestObject1(unittest.TestCase):
  def test_case1(self):
    ...some code...
    ...some assertions...

if __name__ == '__main__':
  unittest.main()

文件:unittest.subfolder2.TestObject2.py

class TestObject2(unittest.TestCase):
  def test_case1(self):
    ...some code...
    ...some assertions...

if __name__ == '__main__':
  unittest.main()

从 'unittest' 上方的顶级目录开始,我试图通过 unittest.discover 查找并运行我的所有测试:

import unittest

loader = unittest.TestLoader()
suite = loader.discover('unittest')
unittest.TextTestRunner().run(suite)

当我这样做时,我收到错误 `ModuleNotFoundError: No module named 'subfolder1.TestObject1'

我做错了什么?

【问题讨论】:

  • 对于第二个单元测试,是直接从那个文件复制过来的吗?如果是,请检查类名“TestObject1”是否应该是“TestObject2”?
  • 这是我修正的一个错字。我确实想出了一个迂回的解决方案并将其发布为答案。

标签: python unit-testing subdirectory


【解决方案1】:

一个好的方法是从命令行运行子目录中的所有测试。为了在子目录中找到以下文件“TestObject1.py, TestObject2.py, ...”,您可以在命令行中运行以下命令:

python -m unittest discover -p 'Test*.py'

此外,importmodule 目录中需要 __init__.pyPython unittest discovery with subfolders

文件 unittest.subfolder1.TestObject1.py 和 unittest.subfolder2.TestObject2.py 中需要 import unittest

也可以使用 -s 参数显式定义发现开始的目录

python -m unittest discover [options]

-s directory     Directory to start discovery ('.' default)
-p pattern       Pattern to match test files ('test*.py' default)

如果您使用的是 unittest2,它带有一个脚本 unit2。命令行用法为:

unit2 discover unit2 -v test_module

【讨论】:

  • 这对我不起作用。我从顶层目录、单元测试目录上方的目录、单元测试目录运行您的命令,然后导航到其中包含测试文件的单个文件夹。每次收到消息:Ran 0 tests in 0.000s
  • 此外,__init__.py 在导入和模块目录中是必需的。
【解决方案2】:

不要将你的目录命名为unittest,它可能与标准库冲突。

您还需要在所有目录(subfolder1 等)中创建一个名为 __init__.py 的文件,以便它们成为包并且可以导入其内容。

【讨论】:

  • 是的,看来您不能直接从unittest 目录运行测试,但我从unittest.subdirectory 运行单元测试没有问题。初始化文件也没有帮助。我确实创建了一个我发布的解决方案。
【解决方案3】:

所以我不得不自己解决问题,但至少我可以让它们都使用上述文件结构运行。它要求我每次给它一个新的文件路径时都重新实例化TestLoader和TestSuite,所以首先我需要在unittest目录中收集所有相关的文件路径。

import os
import unittest
import traceback


class UnitTestLauncher(object):

  def runTests(self):
    #logging.INFO("Running unit tests...")


    lsPaths = []

    #Find all relevant subdirectories that contain unit tests
    #Exclude 'unittest' directory, but include subdirectories, with code `path != 'unittest'`
    for path,subdirs,files in os.walk('unittest'):
      if "pycache" not in path and path != 'unittest':
        lsPaths.append(path)

    #loop through subdirectories and run individually
    for path in lsPaths:
      loader = unittest.TestLoader()
      suite = unittest.TestSuite()
      suite = loader.discover(path)
      unittest.TextTestRunner().run(suite)

这个解决方案并不完美,每个不同的目录都会作为一行输出,因此您必须手动查看每一行以查找失败的测试。

【讨论】:

    【解决方案4】:

    老问题,但是,哦,太新了。我是 Python 的新手,来自强类型语言,虽然语言本身没问题(ish),但让生态系统中的一切正常工作的约定、工具和变通办法会让你发疯。我在不同的子目录中运行单元测试时遇到了困难,这就是我解决它的方法。 首先,将你测试的代码,打包成一个包。像这样组织你的目录:

    Work
    |
    +---PkToTest
    |   |
    |   +--- __init__.py
    |   +--- a.py
    |   +--- <other modules>.py
    |
    +---Tests (for PKToTest)
        |
        +--- test_a.py
    

    PkToTest 由于 init.py 文件而成为一个包。在 test_a.py 中确保您的 sys.path 将包含 PkToTest 的路径(绝对路径不是相对的)。我是这样做的:

    import sys
    sys.path.insert(0, "<absolute path to parent of PkTotest directory>")
    
    import unittest
    from PkToTest import a
    
    class aTestSuite(unittest.TestCase):
        def test1(self):
           self.assertEqual(a.fnToTest(), ...)
    

    【讨论】:

      【解决方案5】:

      在我的项目中,所有文件夹都是文件夹(不是模块),它们具有以下结构:

      文件夹 > 子文件夹 > 子文件夹 > 测试 > test_xxxx.py
      文件夹 > 子文件夹 > 子文件夹 > xxxx.py

      所以我从这里修改了答案,并且还参与了How do I run all Python unit tests in a directory? 并想出了这个:

      import os, unittest
      
      testFolderPaths = []
      
      for path, subdirs, files in os.walk(os.getcwd()):
          for file in files:
              if file.startswith("test_") and file.endswith(".py"):
                  testFolderPaths.append(path)
      
      for path in testFolderPaths:
          print(f"Running tests from {path}...")
          loader = unittest.TestLoader()
          suite = loader.discover(path)
          runner = unittest.TextTestRunner()
          result = runner.run(suite)
          print(f"RUN {result.testsRun} Tests. PASSED? {result.wasSuccessful()}")
      

      如果任何测试失败,它会抛出错误并显示哪个测试失败了。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2010-12-16
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-08-20
        • 2017-08-11
        相关资源
        最近更新 更多