2014-02-25 209 views
4

我正在編寫一個測試腳本,其中包含針對不同測試的不同功能。我希望能夠隨機選擇要運行的測試。我已經用下面的函數實現了這個...隨機選擇函數

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

如果每個可能的測試函數都採用不同類型的參數,並且需要打印不同的日誌記錄消息,那麼執行此操作並不是一個好方法。 – geoffspear

+0

「我希望能夠隨機選擇一個測試運行」 - 爲什麼?爲什麼不直接運行所有的測試? – mgilson

+0

@mgilson有幾個原因。首先有幾千個不同的測試運行。每次腳本運行時都不會涵蓋所有選項,因此應該運行隨機分類。其次,任何測試順序都可能發生的事實本身就是一個考驗。有時訂單可能導致失敗。我打算有一個選擇,以貫穿全部。 – Marmstrong

回答

3

您可以創建功能在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 

你必須讓每個函數採取同樣的參數這種方式,所以你可以用同樣的方式給他們打電話。

3

如果你需要有功能的一些人類可讀的名字,你可以把它們連同功能存儲在字典中。我希望你通過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())) 
+0

'd'是什麼?爲什麼不只是隨機選擇一個值呢? '選擇(list(test_options.values()))' – mgilson

+0

@mgilson對不起,修正了這個問題,是我測試中剩下的,我把'test_options'命名爲'd',忘了修復。我也會添加你的例子。有沒有理由你調用'list(test_options.values())'而不是'test_options.values()'? – msvalkon

+0

python3.x兼容性。 IIRC,'choice'需要一個列表(或至少一個可索引的對象)。由於'dict'對象沒有順序,所以在python3.x中,你不能索引'dict.values()',所以它不再是一個有效的輸入。既然你沒有*那麼多的選擇,額外的'list'調用在性能上應該是微不足道的,它會讓你的代碼向前兼容。 – mgilson

0

如果包裹您的測試選擇功能,並在一類測試本身,你可以做到以下幾點:

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的信息

0

除了其他選項,請看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)() 

這使您可以規範化每個測試函數的參數列表。

1

我要去上肢體這裏建議大家實際使用這個真正的單元測試框架。 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開頭)。它還會告訴您有關哪些測試運行以及哪個測試失敗的信息等。