简体   繁体   English

随机选择功能

[英]Randomly select functions

I am writing a test script which contains different functions for different tests. 我正在编写一个测试脚本,其中包含不同测试的不同功能。 I would like to be able to randomly select a test to run. 我希望能够随机选择要运行的测试。 I have already achieved this with the following function... 我已经通过以下功能实现了这一目标......

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)

However, I want to be to add further test functions without having to modify the random test select function. 但是,我希望在不必修改随机测试选择功能的情况下添加更多测试功能。 All I would like to do is add in the test function to the script. 我想要做的就是在脚本中添加测试功能。 Additionally I would also like a way to selecting which test will be included in the random selection. 另外,我还想要一种方法来选择哪个测试将包含在随机选择中。 This is what the variable test_options does. 这就是变量test_options的作用。 How would I go about changing my random generate function to achieve this? 我将如何改变我的随机生成函数来实现这一目标?

EDIT: I got around the fact that all the tests might need different arguments by including them all in a test class. 编辑:我解决了所有测试可能需要不同的参数,将它们全部包含在测试类中。 All the arguments will be passed into the init and the test functions will refer to them using "self." 所有参数都将传递给init,测试函数将使用“self”引用它们。 when they need a specific variable... 当他们需要一个特定的变量时......

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()

You can create a list of functions in python which you can call: 您可以在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

You have to make each function take the same arguments this way, so you can call them all the same way. 您必须使每个函数以这种方式使用相同的参数,因此您可以以相同的方式调用它们。

If you need to have some human readable names for the functions, you can store them in a dictionary, together with the function. 如果需要为函数提供一些人类可读的名称,可以将它们与函数一起存储在字典中。 I expect that you pass the control_obj to every function. 我希望你将control_obj传递给每个函数。

EDIT: This seems to be identical to the answer by @Ikke, but uses the dictionary instead of a list of functions. 编辑:这似乎 @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)

Or you could pick out a test from test_options.values() . 或者您可以从test_options.values()选择一个测试。 The 'extra' call to list() is because in python 3.x, dict.values() returns an iterator. list()的'额外'调用是因为在python 3.x中, dict.values()返回一个迭代器。

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

I'm gonna go out on a limb here and suggest that you actually use a real unittest framework for this. 我要在这里走出去,并建议你实际上使用一个真正的单元测试框架。 Python provides one -- conveniently name unittest . Python提供一个-方便命名unittest To randomly run a test, it would work like this: 要随机运行测试,它将如下工作:

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()

To run all the tests, instead you would use: unittest.main() -- I suppose you could toggle which happens via a simple commandline switch. 要运行所有测试,请使用: unittest.main() - 我想你可以通过一个简单的命令行开关来切换。

This has the huge advantage that you don't need to keep an up-to-date list of tests separate from the tests themselves. 这具有巨大的优势,您无需保持与测试本身分开的最新测试列表。 If you want to add a new test, just add one and unittest will find it (as long as the method name starts with test ). 如果你想添加一个新的测试,只需添加一个, unittest将找到它(只要方法名称以test开头)。 It will also tell you information about which test runs and which one fails, etc. 它还会告诉您有关哪些测试运行以及哪些测试失败等信息。

If you wrapped your test selecting function and the tests themselves in a class, you could do the following: 如果您将测试选择功能和测试本身包装在一个类中,则可以执行以下操作:

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()

This makes it easy to add tests without the need to change any other code. 这使得添加测试变得容易,而无需更改任何其他代码。 Here is info on getattr 这是关于getattr的信息

In addition to the other options, look at functools.partial . 除了其他选项,请查看functools.partial It allows to create closures for functions: 它允许为函数创建闭包:

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)()

This lets you normalize the argument list for each test function. 这使您可以规范化每个测试函数的参数列表。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM