2017-05-30 107 views
0

這裏是我的情況:使用反射來設置的屬性在單元測試

我創建了一個抽象類,以減少重複代碼,並執行由該擴展這個類的具體類實現的一些方法。

 
abstract class BaseClass 
{ 
    protected $arrayField; 

    ... 

    public function getModifiedArrayField($constraints) 
    { 
     // do things to $arrayField and return a modified 
     // version of the arrayField. Depends only on the 
     // $constraints and some `array_*` functions 
     return $modifiedArray; 
    } 

    // ... some other methods for reducing code duplication 

    // ... abstract methods that needs to be implemented 

} 

我認爲這將是檢驗在抽象類本身的具體方法是個好主意。

$arrayField將由具體類中的抽象方法填充。

因爲我想測試修改該屬性(但不會改變)的方法的功能,所以我寫了如下的單元測試。現在

 

class BaseClassTest extents PHPUnit_Framework_TestCase 

    private $sut; 

    public function setUp() 
    { 
     $mockObj = $this->getMockFromAbstractClass(BaseClass::class); 
     $ref = new ReflectionClass($mockObj); 
     $ref_prop = $ref->getProperty('arrayField'); 
     $ref_prop->setAccessible(true); 
     $ref_prop->setValue($mockObj, [an_array]); 
     $this->sut = $mockObj; 
    } 

    // .. some test methods that tests methods of abstract class 

    public function testGetModifiedArrayFieldReturnsExpectedArray() 
    { 
     $expected = [array_i_expect]; 
     $actual = $this->sut->getModifiedArrayField([constraints_i_provide]); 

     $this->assertEquals($expected, $actual); 
    } 

,我看這不是使用反射來改變只是爲了測試的緣故知名度一個很好的做法。

所以我兩個問題:

  1. 是否測試社區發現這種方法只是一個「小過失」,而不是一個大罪?
  2. 我應該不同地設計這個類,以便我可以擺脫反射?如果是的話,你會建議任何方法?

UPDATE:

answer通過Schleis讓我思考,並在互聯網上一些聊天與我的朋友和一些資源後,我選擇引入一個額外的參數的函數來解決這個問題我需要測試。

我將繼續嘗試將函數泛化並將其移動到ArrayHelper類的類中,該類使1)測試更容易,2)允許代碼的其他部分在需要時使用該方法。

回答

1

使用反射的問題是你正在暴露類的內部。單元測試有助於證明您的代碼正常工作,但也會允許您重構事物並驗證您是否未更改任何當前功能。

所以使用反射來改變內部屬性的可見性意味着你可以刪除/以後更改屬性。例如,你可能會發現你可以即時計算它或類似的東西。

很難在測試一個類是代碼味道。

爲什麼$arrayField只能通過一個抽象的方法來設置?如果我在調用getModifiedArrayField()之前沒有在此類的實現中調用該方法,會發生什麼情況?

這是很難告訴你正在使用這個類,並根據您的職位名稱和描述的方法意圖。不過,我認爲你可能需要考慮更多你希望你的班級在做什麼。並改變你的類要求其在構造函​​數中提供一個$arrayField或提供一個簡單的公共方法來設置這個類中的值。

+0

感謝您的回答。關於你的問題:抽象方法就像一個水化器,它從數據提供者中填充'arrayField'的值。我想測試的方法只是將數據轉換爲不同的格式,以便預先存在的代碼庫可以對返回的數據執行其操作。我想一個更好的想法是將轉換移動到一個單獨的類,並在任何此類返回時運行該轉換,或者只是向該函數傳遞一個額外的參數,儘管我不太確定這種性能開銷。 – cipher