2012-03-02 11 views
1

同じ属性に対して複数の値をテストするにはどうすればよいですか?PHPUnit、複数の値をテストする

class Test { 

    private $_optionalValue = null; 

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

だからここに、 "$ _optionalValueは、" NULLまたはユーザー定義の値かもしれないが、私はこのようなPHPUnitでチェックする場合:$ optionalValueがStringではないので

$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) 
     ) 
    ) 
); 

ザ・正規表現アサーションが失敗しました(デフォルトではヌルです)

+2

なぜこれをこの奇妙な方法でテストしていますか?内部状態ではなくクラスの動作をテストすることになっています。値を設定します。値を取得します。同じことを確認してください。それだけであなたがする必要があります。 – Gordon

+0

@hakre彼のテストでXORの問題は何ですか? – meze

+0

setter(私の場合はもっと複雑です)をsettedプロパティの代わりにテストしますか?そして、私はXORを使用しました。なぜなら属性はNULL XOR(文字列と正規表現の正規表現)でなければならなかったからです。私はORを使用していたかもしれません。 – kitensei

答えて

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

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}/') 
     ) 
    ) 
); 

ところで、私はあなたがオフに優れているa)は、このように内部状態をテストしていないことに同意しないとあなたが期待する値を知っているように、b)は、あなたのテストを設計する必要があります。各テストでは、システムを単一の期待状態にする必要があります。乱数を使用するコードでも、スタブを使用して固定シーケンスを置き換える必要があります。複数の可能性を可能にするテストは疑わしい。

+0

実際に私はより良いテストを設計しますが、私はこの使用法を知らなかった。 – kitensei

関連する問題