【问题标题】:How to benchmark unit tests in Python without adding any code如何在不添加任何代码的情况下在 Python 中对单元测试进行基准测试
【发布时间】:2014-06-10 20:10:00
【问题描述】:

我有一个 Python 项目,其中包含已经实施的大量测试,我想开始对它们进行基准测试,以便比较代码、服务器等随时间推移的性能。以类似于鼻子的方式定位文件没有问题,因为无论如何我的所有测试文件的名称中都有“测试”。但是,我在尝试动态执行这些测试时遇到了一些麻烦。

截至目前,我可以运行一个脚本,该脚本将目录路径作为参数并返回如下文件路径列表:

def getTestFiles(directory):
    fileList = []
    print "Searching for 'test' in " + directory
    if not os.path.isdir(os.path.dirname(directory)):
        # throw error
        raise InputError(directory, "Not a valid directory")
    else:
        for root, dirs, files in os.walk(directory):
            #print files
            for f in files:
                if "test" in f and f.endswith(".py"):
                    fileList.append(os.path.join(root, f))
    return fileList

# returns a list like this:
# [  'C:/Users/myName/Desktop/example1_test.py',
#    'C:/Users/myName/Desktop/example2_test.py',
#    'C:/Users/myName/Desktop/folder1/example3_test.py',
#    'C:/Users/myName/Desktop/folder2/example4_test.py'...  ]

问题是这些文件可能有不同的语法,我试图弄清楚如何处理。例如:

TestExampleOne:

import dummy1
import dummy2
import dummy3

class TestExampleOne(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        # set up

    def test_one(self):
        # test stuff
    def test_two(self):
        # test stuff
    def test_three(self):
        # test stuff

    # etc...

TestExampleTwo:

import dummy1
import dummy2
import dummy3

def setup(self):
    try:
        # config stuff
    except Exception as e:
        logger.exception(e)

def test_one():
    # test stuff
def test_two():
    # test stuff
def test_three():
    # test stuff

# etc...

TestExampleThree:

import dummy1
import dummy2
import dummy3

def setup(self):
    try:
        # config stuff
    except Exception as e:
        logger.exception(e)

class TestExampleTwo(unittest.TestCase):
    def test_one(self):
        # test stuff
    def test_two(self):
        # test stuff
    # etc...

class TestExampleThree(unittest.TestCase):
    def test_one(self):
        # test stuff
    def test_two(self):
        # test stuff
    # etc...

# etc...

我真的很希望能够编写一个模块,它在目录中搜索名称中包含“test”的每个文件,然后执行每个文件中的每个单元测试,为每个测试提供执行时间。我认为像 NodeVisitor 这样的东西是在正确的轨道上,但我不确定。即使是从哪里开始的想法也将不胜感激。谢谢

【问题讨论】:

  • 不是您所要求的,但相关的是vbench。它跨版本控制运行一组基准测试。请注意,随着时间的推移,测试可能会改变它们所做的事情。
  • 找到 -name '*test*.py' |而读t;做时间$t;完成

标签: python unit-testing testing benchmarking


【解决方案1】:

使用nose 测试运行器将有助于discover the tests,设置/拆卸功能和方法。

nose-timer 插件有助于进行基准测试:

鼻子测试的计时器插件回答了这个问题:多少时间 每次考试都要考吗?


演示:

  • 假设您有一个名为 test_nose 的包,其中包含以下脚本:

    • test1.py:

      import time
      import unittest
      
      class TestExampleOne(unittest.TestCase):
          @classmethod
          def setUpClass(cls):
              cls.value = 1
      
          def test_one(self):
              time.sleep(1)
              self.assertEqual(1, self.value)
      
    • test2.py:

      import time
      
      value = None
      
      def setup():
          global value
          value = 1
      
      def test_one():
          time.sleep(2)
          assert value == 1
      
    • test3.py:

      import time
      import unittest
      
      value = None
      
      def setup():
          global value
          value = 1
      
      class TestExampleTwo(unittest.TestCase):
          def test_one(self):
              time.sleep(3)
              self.assertEqual(1, value)
      
      class TestExampleThree(unittest.TestCase):
          def test_one(self):
              time.sleep(4)
              self.assertEqual(1, value)
      
  • 安装nose 测试运行器:

    pip install nose
    
  • 安装nose-timer插件:

    pip install nose-timer
    
  • 运行测试:

    $ nosetests test_nose --with-timer
    ....
    test_nose.test3.TestExampleThree.test_one: 4.0003s
    test_nose.test3.TestExampleTwo.test_one: 3.0010s
    test_nose.test2.test_one: 2.0011s
    test_nose.test1.TestExampleOne.test_one: 1.0005s
    ----------------------------------------------------------------------
    Ran 4 tests in 10.006s
    
    OK
    

结果实际上很方便地突出显示:

颜色可以通过--timer-ok--timer-warning参数控制。

请注意,添加了 time.sleep(n) 调用以使手动减速以清楚地看到影响。另请注意,value 变量在“设置”函数和方法中设置为1,然后在测试函数和方法中,value 被断言为1 - 这样您就可以看到设置函数的工作。

UPD(从脚本运行 nosenose-timer):

from pprint import pprint
import nose
from nosetimer import plugin

plugin = plugin.TimerPlugin()
plugin.enabled = True
plugin.timer_ok = 1000
plugin.timer_warning = 2000
plugin.timer_no_color = False


nose.run(plugins=[plugin])
result = plugin._timed_tests
pprint(result)

将其保存到test.py 脚本中并将目标目录传递给它:

python test.py /home/example/dir/tests --with-timer

result 变量将包含:

{'test_nose.test1.TestExampleOne.test_one': 1.0009748935699463,
 'test_nose.test2.test_one': 2.0003929138183594,
 'test_nose.test3.TestExampleThree.test_one': 4.000233173370361,
 'test_nose.test3.TestExampleTwo.test_one': 3.001115083694458}

【讨论】:

  • 这正是我正在寻找的。我将在星期一对其进行测试,并在有任何问题时与您联系——届时将接受。谢谢。
  • 我需要能够将这些运行时间值放入一个模块中,以便我可以存储它们并将它们放入一个漂亮的图表中,并与以前的测试进行比较。我该怎么做呢?
  • 换句话说,我如何从 Python 模块运行 nosetests test_nose --with-timer 并将这些运行时间放入某种列表中?
  • @weskpga 更新了答案。请参阅UPD 部分。希望对您有所帮助。
  • 是的,这很完美。现在最后一个问题:我将如何传递要使用此脚本运行的目录的绝对路径?我会像nose.run(argv=['home/example/directory/here', '--with-timer'], plugins=[plugin]) 那样做吗?我接受了您的回答,因为您已经提供了很多帮助。
猜你喜欢
  • 2018-11-12
  • 2011-05-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-09-20
  • 1970-01-01
  • 2017-12-01
相关资源
最近更新 更多