4

0 から 6 までの 3 つのランダムな要素配列を返す関数があります。すべての要素が同じ値を持つことはできません (同じ値を持つ 2 つの要素を持つことはできますが、3 つにすることはできません)。以下はサンプルコードです。

public function getRandom() {
    $array = array(0, 0, 0);
    do {
        $array[0] = rand(0, 6);
        $array[1] = rand(0, 6);
        $array[2] = rand(0, 6);
    } while(($array[0] == $array[1]) && ($array[0] == $array[2]));
    return $array;
}

私はユニットテストに少し慣れていません。これをテストすることを考えることができると思うのは

  1. この関数を 1,000 回テストし、0 ~ 6 のデータが返されるかどうかを確認します。3 つの要素すべてが同じ値を持つことはできません。
  2. 関数 rand() をオーバーライドして、必要なものを返す方法を見つけます。
    • 3 つの要素がすべて同じ値を持つ戻り値、次に同じ値を持つ 2 つの要素を持つ戻り値。次に、すべての要素が異なる値を持つ値を返します。

アプローチがあるかどうか、またはこの場合の私のアプローチのどれが優れているか疑問に思います。

4

2 に答える 2

6

あなたが正しく推測したように、ランダム性を確実にテストすることはできません。

ランダム性を制御する問題は、アーキテクチャの弱点を示しています。テストしたいクラスとメソッドがありますがrand()、テスト中に呼び出される関数 ( ) を制御できません。

最初は奇妙に聞こえるかもしれませんが、「制御された」ランダム性でテストしたい場合は、ランダム関数を何らかの方法でモックする必要があるため、テスト中に呼び出しを傍受し、定義されたテスト値を返すことができるようにするその PHP 関数のラッパーが必要になります。時間。

ちょっと考えてみてください: ランダム性のためのメソッドを持つクラスがあり、そのクラスのインスタンスがテスト対象のクラスに注入されてランダムな値を提供する場合、テスト中にそのオブジェクトをモックして戻り値を定義できます。 . 任務完了。:)

rand()すべての呼び出しを同じ名前の PHP 関数に渡す単一のメソッドを持つ単一のオブジェクトをインスタンス化するのは奇妙に思えます。動作させるために、実行時にそのオブジェクトをテスト済みのクラスに渡す必要があるのはさらに奇妙です。ただし、そのランタイム依存関係を持つ必要はありません。テスト済みのクラスをリファクタリングして、注入された乱数プロバイダーがあるかどうかを調べて使用し、そうでない場合はrand()直接使用することもできます。

クラスの再作業をさらに減らしたい場合は、組み込みの PHP 関数をオーバーライドするトリックがあります。クラスが名前空間内にあり、ネイティブ PHP 関数を呼び出す場合、その関数は最初にその名前空間内で検索されます。rand()テスト ファイルで指定された関数を、テスト対象のクラスと同じ名前空間で宣言すると、そのクラスは、PHP の関数ではなく、名前空間が設定された関数を呼び出します。次に、そのモック関数の戻り値を事前に定義する方法を考えるだけで済みますが、おそらくグローバル変数または定義済みの「ランダム性」で満たされるテストケース クラスの静的プロパティを使用できます。

namespace MyNameSpace;
function rand() {
    return array_shift(RandomTest::$randomValues);
}

class RandomTest extends PHPUnit_Framework_TestCase {
    public static $randomValues = array();
    public function testSomeRandomness() {
        self::$randomValues = array(0,0,0,0,1,2);
        // ... test 
    }
}

その仕事があれば、本当の PHPUnit モック オブジェクトを選択し、それをクラスに挿入するためのセッターを選択し、デフォルトで を呼び出すオプションの依存関係としてコーディングしますrand()

于 2013-09-11T21:14:58.057 に答える
1

2 番目の解決策は確かに最適です。もちろん、これには rand 関数をスタブ化するための何らかのインターフェイスを作成する必要があります。

コードを変更できない場合 (つまり、サード パーティのコード)、最初の解決策が可能な唯一の解決策です。単体テストは高速である必要があり、多くの反復はこれに役立たないことを覚えておいてください。

3 番目のオプションとして、いわゆる網羅的テストを使用できます。可能性のあるすべての値を使用し、単体テストを作成して値のすべての組み合わせをテストします。つまり、[0, 0, 0]、[0, 0, 1] ... [5, 5、5]。これは、6^3 = 216 個の単体テストを意味しますが、すべての組み合わせがテストされ、ソリューション 1 よりも優れていることを確認できます。

于 2013-09-11T12:28:31.103 に答える