2016-05-31 44 views
0

我有一個功能,它考慮三種不同的情況,並針對每種情況調用不同的功能,如在下面PyTest:測試該功能被稱爲if語句

def my_fun(input): 
if input == 1: 
    fun1() 
if input == 2: 
    fun2() 
if input == 3: 
    fun3() 

的例子,我還想寫功能my_fun使用py.test的測試,但我不知道如何測試給定輸入是否調用了正確的函數?

+0

只要輸出是正確的,你真的關心哪個函數被調用? – fmarc

+0

@fmarc當然,我可以測試三種可能的輸入,並檢查輸出,但這意味着我必須運行所有三個函數fun1,fun2,fun3,我只是尋找一個更優雅的方式來做到這一點 – Ziva

+0

會它也適合你直接爲fun1/2/3寫測試嗎? my_fun()包含很少的代碼,所以無論如何,從編寫測試中獲得的代碼都很少。 – fmarc

回答

2

如果所有的fun1(),fun2()和fun3()都返回結果,我會參數化。

# Here an example of functions to be tested 

def fun1(): 
    return 1 
def fun2(): 
    return 2 
def fun3(): 
    return 3 

def my_fun(input): 
    if input == 1: 
     return fun1() 
    if input == 2: 
     return fun2() 
    if input == 3: 
     return fun3() 

這裏在測試矩陣中。預期的結果也是測試函數的調用,所以你可以匹配測試函數調用(如你的問題問):

# Parametrized test 
import pytest 

@pytest.mark.parametrize("test_input, expected", [(1, fun1()), (2, fun2()), (3, fun3())]) 
# --------------------------------------- 
# test_input | 1 | 2 | 3 | 
# --------------------------------------- 
# expected | fun1() | fun2() | fun3() | 
# --------------------------------------- 
def test_my_fun(test_input, expected): 
    assert my_fun(test_input) == expected 

試運行:

mac: py.test -v test_parametrization.py 
=================================================================================== test session starts ==================================================================================== 
platform darwin -- Python 2.7.11, pytest-2.9.1, py-1.4.31, pluggy-0.3.1 -- /Library/Frameworks/Python.framework/Versions/2.7/Resources/Python.app/Contents/MacOS/Python 
cachedir: .cache 
rootdir: /Users/user/Repos/playground, inifile: 
plugins: hidecaptured-0.1.2, instafail-0.3.0 
collected 3 items 

test_parametrization.py::test_my_fun[1-1] PASSED 
test_parametrization.py::test_my_fun[2-2] PASSED 
test_parametrization.py::test_my_fun[3-3] PASSED 

================================================================================= 3 passed in 0.01 seconds ================================================================================= 
-3

爲什麼多個if語句而不是elif?他們的條件是相互排斥的,那麼爲什麼要浪費其他支票但無論如何,虛擬打印如何如下:

def my_fun(input): 
    if input == 1: 
     fun1() 
     print("Function 1 executed ?") 
    elif input == 2: 
     fun2() 
     print("Function 2 executed ?") 
    elif input == 3: 
     fun3() 
     print("Function 3 executed ?") 

如果我有足夠的聲譽,我只是評論btw。 #JustWannaGetTo50

+0

他用'py.test'說。 –

3

正如@fmarc所評論的那樣,調用哪個函數並不比測試my_fun做的是正確的事情重要。但是,你可以模擬三個函數中的每一個,然後測試正確的函數是否獨立於每個函數的實際功能。 (注意:mock是在Python 2第三方模塊,你需要安裝;它可在Python 3.3()作爲unittest.mock標準庫?)

一個簡單的例子:

import mock 

def test_my_fun(): 
    with mock.patch('fun1', wraps=fun1) as mock_fun1: 
     with mock.patch('fun2', wraps=fun2) as mock_fun2: 
      with mock.patch('fun3', wraps=fun3) as mock_fun3: 
       my_fun(1) 
       mock_fun1.assert_called_with() 
       mock_fun2.assert_not_called() 
       mock_fun3.assert_not_called() 

檢查您的mock安裝文檔以查看哪些方法受支持。

+0

請注意,自Py2.7以來,您可以在一個with-statement中使用多個上下文管理器。在這種情況下不太可讀:-),但保存縮進。 – fmarc

+0

哦,對。我一直呆在2.6這麼久,我忘了什麼時候加入。 – chepner

+1

還有一個[pytest-mock](https://github.com/pytest-dev/pytest-mock),它給了你一個'mocker' fixture(IMHO)簡化了這一點,你可以簡單地執行'mock_fun1 = mock.match('fun1',wrapps = fun1)等等,測試後夾具將負責清理。 –