【问题标题】:Randomly select functions随机选择函数
【发布时间】:2014-03-27 20:04:45
【问题描述】:

我正在编写一个测试脚本,其中包含针对不同测试的不同功能。我希望能够随机选择一个测试来运行。我已经通过以下功能实现了这一点...

test_options = ("AOI", "RMODE")

def random_test(test_options, control_obj):
  ran_test_opt = choice(test_options)

  if ran_test_opt.upper() == "AOI":
     logging.debug("Random AOI Test selected")
     random_aoi()
  elif ran_test_opt.upper() == "RMODE":
    logging.debug("Random Read Mode Test selected")
    random_read_mode(control_obj)

但是,我想添加更多测试功能,而无需修改随机测试选择功能。我想做的就是将测试功能添加到脚本中。此外,我还想要一种方法来选择将哪个测试包含在随机选择中。这就是变量 test_options 的作用。我将如何改变我的随机生成功能来实现这一点?

编辑:我通过将所有测试都包含在测试类中来解决所有测试可能需要不同参数的事实。所有参数都将传递到 init 中,测试函数将使用“self”引用它们。当他们需要一个特定的变量时......

class Test(object):
  """A class that contains and keeps track of the tests and the different modes"""

  def __init__(self, parser, control_obj):
    self.parser = parser
    self.control_obj = control_obj

  def random_test(self):
    test_options = []
    for name in self.parser.options('Test_Selection'):
        if self.parser.getboolean('Test_Selection', name):
            test_options.append(name.lower())

    ran_test_opt = choice(test_options)
    ran_test_func = getattr(self, ran_test_opt)
    ran_test_func()

  #### TESTS ####
  def random_aoi(self):
    logging.info("Random AOI Test")
    self.control_obj.random_readout_size()

  def random_read_mode(self):
    logging.info("Random Readout Mode Test")
    self.control_obj.random_read_mode()

【问题讨论】:

  • 如果每个可能的测试函数都采用不同类型的参数,并且需要打印不同的日志消息,那么这并不是一个很好的方法。
  • “我希望能够随机选择一个测试来运行”——为什么?为什么不直接运行所有测试?
  • @mgilson 有几个原因。首先,有数千种不同的测试要运行。每次运行脚本时,它都不会涵盖所有选项,因此应运行随机分类。其次,任何测试顺序都可能发生的事实本身就是一个测试。有时订单会导致失败。我计划也可以选择只运行整个批次。

标签: python function variables random


【解决方案1】:

如果您需要为函数提供一些人类可读的名称,您可以将它们与函数一起存储在字典中。我希望您将control_obj 传递给每个函数。

编辑:这似乎与@Ikke 的答案相同,但使用字典而不是函数列表。

>>> test_options = {'AOI': random_aoi, 'RMODE': random_read_mode}

>>> def random_test(test_options, control_obj):
...    ran_test_opt = test_options[choice(test_options.keys())]
...    ran_test_opt(control_obj)

或者您可以从test_options.values() 中挑选一个测试。对list() 的“额外”调用是因为在python 3.x 中,dict.values() 返回一个迭代器。

>>> ran_test_opt = choice(list(test_options.values()))

【讨论】:

  • 什么是d?为什么不随机选择其中一个值呢? choice(list(test_options.values()))
  • @mgilson 抱歉修复了这个问题,是我测试的剩余部分,我将 test_options 命名为 d,忘记修复了。我也会添加你的例子。你打电话给list(test_options.values())而不是test_options.values()有什么原因吗?
  • python3.x 兼容性。 IIRC,choice 需要一个列表(或至少一个可索引对象)。由于dict 对象没有顺序,在python3.x 中,您不能索引dict.values(),因此它不再是可供选择的有效输入。由于您没有那么很多选择,因此对list 的额外调用在性能方面应该可以忽略不计,并且它将使您的代码向前兼容。
  • @mgilson 谢谢,我有点期待它是关于 python 3.x 的。我也会解决这个问题。
【解决方案2】:

我要在这里冒险并建议您为此使用真正的单元测试框架。 Python 提供了一个——方便地命名为unittest。要随机运行测试,它的工作方式如下:

import unittest

class Tests(unittest.TestCase):
    def test_something(self):
        ...
    def test_something_else(self):
        ...


if __name__ == '__main__':
    tests = list(unittest.defaultTestLoader.loadTestsFromTestCase(Tests))
    import random
    # repeat as many times as you would like...
    test = random.choice(tests)
    print(test)
    test()

要运行所有测试,您可以使用:unittest.main() -- 我想您可以通过简单的命令行开关来切换。

这有一个巨大的优势,即您不需要将最新的测试列表与测试本身分开。如果要添加新的测试,只需添加一个,unittest 就会找到它(只要方法名称以test 开头)。它还会告诉您有关哪些测试运行以及哪些测试失败等信息。

【讨论】:

    【解决方案3】:

    除了其他选项,请查看functools.partial。它允许为函数创建闭包:

    from functools import partial
    
    def test_function_a(x,y):
       return x+y
    
    def other_function(b, c=5, d=4):
       return (b*c)**d
    
    def my_test_functions(some_input):
       funclist = (partial(test_function_a, x=some_input, y=4),
                   partial(other_function, b=some_input, d=9))
       return funclist
    
    random.choice(funclist)()
    

    这让您可以标准化每个测试函数的参数列表。

    【讨论】:

      【解决方案4】:

      如果您将测试选择功能和测试本身封装在一个类中,您可以执行以下操作:

      from random import choice
      
      class Test(object):
          """ Randomly selects a test from the methods with 'random' in the name """
      
          def random_aoi(self):
              print 'aoi'
      
          def random_read_mode(self):
              print 'read_mode'
      
          def random_text(self):
              print 'test'
      
          # add as many tests as needed here
      
          # important that this function doesn't have 'random' in the name(in my code anyway)
          def run_test(self): # you can add control_obj to the args 
              methods = [m for m in dir(self) if callable(getattr(self, m)) and 'random' in m]
              test = choice(methods)
              getattr(self, test)() # you would add control_obj between these parens also
      
      
      app = Test()
      app.run_test()
      

      这使得添加测试变得容易,而无需更改任何其他代码。 这是getattr的信息

      【讨论】:

        【解决方案5】:

        您可以在 python 中创建一个可以调用的函数列表:

        test_options = (random_aoi, random_read_mode)
        
        def random_test(test_options, control_obj):
            ran_test_opt = choice(test_options)
            ran_test_opt(control_obj) # call the randomly selected function
        

        你必须让每个函数都以这种方式接受相同的参数,所以你可以用同样的方式调用它们。

        【讨论】:

          猜你喜欢
          • 2016-05-02
          • 1970-01-01
          • 1970-01-01
          • 2021-12-15
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多