2012-03-02 53 views
1

如何爲同一個屬性測試多個值?PHPUnit,測試多個值

class Test { 

    private $_optionalValue = null; 

    function setValue(String $optionalValue) 
    { 
     $this->_optionalValue = $optionalValue; 
    } 
} 

所以在這裏, 「$ _optionalValue」 可能爲NULL或用戶定義的值,但是當我在PHPUnit檢查這樣的:

$optionalValue = PHPUnit_Util_Class::getObjectAttribute($my_object, '_optionalValue'); 

$this->assertThat(
    $optionalValue, 
    $this->logicalXor(
     $this->assertNull($optionalValue), 
     $this->logicalAnd(
      $this->assertAttributeInternalType('string', '_optionalValue', $optionalValue), 
      $this->assertRegExp('/[0-9]{2}:[0-9]{2}:[0-9]{2}/', (string) $optionalValue) 
     ) 
    ) 
); 

正則表達式斷言失敗,因爲$ optionalValue不是一個String (默認爲空)

+2

你爲什麼要用這種奇怪的方式測試它?你應該測試你的班級的行爲而不是內部狀態。設置值。獲得價值。確保它是一樣的。這就是你需要做的。 – Gordon 2012-03-02 10:05:10

+0

@hakre XOR在他的測試中出了什麼問題? – meze 2012-03-02 10:05:44

+0

所以你會測試setter(這在我的情況下更復雜),而不是設置的屬性?並順便說一句,我用異或因爲屬性應該爲空XOR(字符串和匹配的正則表達式) - 我可以使用OR它本來是一樣的 – kitensei 2012-03-02 10:07:25

回答

1

您正在測試一個對象的私有屬性,通常應該避免該對象的私有屬性,因爲這是該單位的內部,您不應該在意這一點。

如果你的單元需要驗證該類的值,通常應該驗證某種類型的值。

因此,您可以將驗證的邏輯封裝到其自己的單元中,例如,驗證程序:

class FooValueValidator implements Validator { 
    /** 
    * @var string 
    */ 
    private $value; 

    /** 
    * @var string 
    */ 
    private $regex = '/[0-9]{2}:[0-9]{2}:[0-9]{2}/'; 

    public function __construct($value) { 
     $this->value = $value; 
    } 

    /** 
    * @return bool 
    */ 
    public function isValid() { 

     if (is_null($this->value)) { 
      return TRUE; 
     } 

     if (!is_string($this->value)) { 
      return FALSE; 
     } 

     $result = preg_match($this->pattern, $this->value); 
     if (FALSE === $result) { 
      throw new Exception(sprintf('Regular expression failed.')); 
     } 
     return (bool) $result; 
    } 
} 

然後,您可以爲驗證器編寫單元測試。然後你就知道你的驗證器工作正常,你可以在任何你喜歡的地方使用它。

class Test { 

    private $_optionalValue = null; 

    /** 
    * @var Validator 
    */ 
    private $_validator; 

    public function __construct(Validator $validator) { 
     $this->_validator = $validator; 
    } 

    function setValue(String $optionalValue) 
    { 
     if (!$this->validator->isValid($optionalValue)) { 
      throw new InvalidArgumentException(sprintf('Invalid value "%s".', $optionalValue)); 
     } 
     $this->_optionalValue = $optionalValue; 
    } 
} 
+0

不錯的解決方案,採納:) – kitensei 2012-03-02 10:30:23

2

你是你的電話裏作出斷言到assertThat,但你需要建立和約束票代替。所有以assert開頭的方法立即評估值,並在不匹配時拋出異常。每個斷言都有一個相應的約束類,其中一些具有工廠方法。

$optionalValue = PHPUnit_Util_Class::getObjectAttribute($my_object, '_optionalValue'); 

$this->assertThat(
    $optionalValue, 
    $this->logicalXor(
     $this->isNull(), 
     $this->logicalAnd(
      new PHPUnit_Framework_Constraint_IsType('string'), 
      new PHPUnit_Framework_Constraint_PCREMatch('/[0-9]{2}:[0-9]{2}:[0-9]{2}/') 
     ) 
    ) 
); 

順便說一句,我不同意,一)你最好不要測試內部狀態,像這樣和b),讓你知道會發生哪些價值你應該設計你的測試。每個測試都應該使系統進入單一的期望狀態。即使使用隨機數的代碼也應該使用存根來代替固定的序列。任何允許多種可能性的測試都是可疑的。

+0

確實我會更好地設計我的測試,但感謝您的答案,我不知道這種用法。 – kitensei 2012-03-04 00:14:14