2012-01-06 85 views
2

我正在編寫單元測試平臺,我希望能夠基於我測試的Web服務中的每個函數動態生成一個函數。動態函數將以Web服務中每個參數的默認(正確)值生成,並允許它們用錯誤測試的不正確值交易。PHP可以像編寫Lisp宏一樣編寫額外的PHP函數嗎?

$arrayOfDefVals = array(123, 'foo'); 

testFunctionGenerator('function1', $arrayOfDefVals); 

//resulting php code: 
function1Test($expectedOutput, $arg1=123, $arg2='foo') 
{ 
    try 
    { 
     $out = function1($arg1, $arg2); 
     if($expectedOutput === $out) 
      return true; 
     else 
      return $out; 
    } 
    catch ($e) 
    { 
     return $e; 
    } 
} 

這讓我很快就會完全傳遞一個錯誤的參數,或任意數量的錯誤參數,一次測試所有的錯誤在web服務相扶。

我的主要問題是: 這甚至可能與PHP? 如果這是不可能的,是否有其他選擇?

編輯:我不是在尋找一個單元測試,我正在嘗試通過這樣做來學習。我沒有在這個代碼示例中尋找建議,這只是我想要做的一個快速示例。我只想知道這是否可能。

+0

如果函數退出或輸出某種錯誤而不是返回錯誤輸入的結果會怎麼樣? – animuson 2012-01-06 18:34:28

+2

出於好奇,你爲什麼要寫一個單元測試平臺,而不是使用已經存在的平臺? – Problematic 2012-01-06 18:39:16

+0

...即http://www.phpunit.de/ – Gordon 2012-01-06 18:42:07

回答

2

我不會嘗試,因爲PHP沒有內置的宏支持。但可能是一些在那個方向:

function function1($param1, $param2) 
{ 
    return sprintf("param1: %d, param2: '%s'\n", $param1, $param2); 
} 

/* Macro: basically a port of your macro as a function */ 

$testFunctionGenerator = function($callback, array $defVals = array()) 
{ 
    $defVals = array_values($defVals); // list, not hash 
    return function() use ($callback, $defVals) 
    { 
     $callArgs = func_get_args(); 
     $expectedOutput = array_shift($callArgs); 

     $callArgs += $defVals; 

     return $expectedOutput == call_user_func_array($callback, $callArgs); 
    }; 
}; 

/* Use */ 

$arrayOfDefVals = array(123, 'foo'); 

$function1Test = $testFunctionGenerator('function1', $arrayOfDefVals); 

var_dump($function1Test("param1: 456, param2: 'foo'\n", 456)); # bool(true) 

也許這是有幫助的,看到Anonymous functions­Docsfunc_get_args­DocsUnion array operator­Docscall_user_func_array­Docs

+0

我知道這不是我的問題,但爲了將來的參考:因爲我使用SoapClient()我不能使用call_user_func_array,我不得不使用$客戶端 - > __ soapCall($回調,$ arrayOfArgs)這是基本上是一樣的東西,只有它實際上適用於Web服務。 – Phil 2012-01-09 21:46:45

2

嗯,首先,你可以在功能設置默認參數:

function function1Test($expectedOutput, $testArg1=123, $testArg2='foo') { 
    ... 
} 

除此之外,我真的不知道你正在努力實現這個「函數發生器」什麼......

+0

我試圖避免必須分別編寫每個測試函數。用一個宏,我可以給它一個來自Web服務的函數列表,然後將有一個測試函數列表。 – Phil 2012-01-06 18:41:39

0

閱讀從手動約call_user_funcfunc_get_args

這個例子應該讓你在正確的軌道上:

<?php 
call_user_func(function($arg) { print "[$arg]\n"; }, 'test'); /* As of PHP 5.3.0 */ 
?> 
0

如果它是一個功能,你必須文件訪問(即,它不是PHP標準庫的一部分,您有權從文件中讀取),你可以做這樣的事情:

假設我們有像這樣的函數位於某個文件中。該文件將被列入(即功能將不得不在PHP的內部符號表):

function my_original_function($param1, $param2) 
{ 
    echo "$param1 $param2 \n"; 
} 

使用ReflectionFunction類獲取有關該功能並在它被定義細節:http://us2.php.net/manual/en/class.reflectionfunction.php

$ reflection = new ReflectionFunction('my_original_function');

接下來,你可以使用反射實例來獲取的路徑文件,該函數的第一個/最後一個行號,並在參數功能:

$file_path = $reflection->getFileName(); 
$start_line = $reflection->getStartLine(); 
$end_line = $reflection->getEndLine(); 
$params = $reflection->getParameters(); 

使用這些,你可以:

  1. 讀出的文件的功能爲一個字符串
  2. 改寫的第一行來改變函數名,使用已知的函數名作爲參考
  3. 改寫第一線,更改參數默認,使用$ PARAMS作爲參考
  4. 編寫修改功能的字符串文件
  5. 包括文件
  6. 瞧!你現在有了新的功能。

取決於它是什麼你實際上試圖完成,你也可能只使用ReflectionFunction :: getClosure()來獲得功能的關閉副本,將其分配到任何你想要的變量,並在那裏定義參數。參見:http://us.php.net/manual/en/functions.anonymous.php。或者你可以實例化多個ReflectionFunctions並用你想要的參數集調用ReflectionFunction :: invoke()/ invokeArgs()。請參閱:http://us2.php.net/manual/en/reflectionfunction.invokeargs.phphttp://us2.php.net/manual/en/reflectionfunction.invoke.php