8

指定されたキーのセットの値を無視しながら、2 つの配列が同じであることをアサートできる PHP 関数が必要です (値のみ、キーは一致する必要があります)。

実際には、配列は同じ構造でなければなりませんが、一部の値は無視できます。

たとえば、次の 2 つの配列を考えてみます。

Array
(
    [0] => Array
        (
            [id] => 0
            [title] => Book1 Title
            [creationDate] => 2013-01-13 17:01:07
            [pageCount] => 0
        )
)

Array
(
    [0] => Array
        (
            [id] => 1
            [title] => Book1 Title
            [creationDate] => 2013-01-13 17:01:07
            [pageCount] => 0
        )
)

key の値を無視すれば、それらは同じですid

また、ネストされた配列の可能性も考慮したいと思います。

Array
(
    [0] => Array
        (
            [id] => 0
            [title] => Book1 Title
            [creationDate] => 2013-01-13 17:01:07
            [pageCount] => 0
        )

    [1] => Array
        (
            [id] => 0
            [title] => Book2 Title
            [creationDate] => 2013-01-13 18:01:07
            [pageCount] => 0
        )
)

Array
(
    [0] => Array
        (
            [id] => 2
            [title] => Book1 Title
            [creationDate] => 2013-01-13 17:01:07
            [pageCount] => 0
        )

    [1] => Array
        (
            [id] => 3
            [title] => Book2 Title
            [creationDate] => 2013-01-13 18:01:07
            [pageCount] => 0
        )
)

テストに必要なので、PHPUnit_Framework_TestCaseを拡張し、アサート関数を使用する次のクラスを作成しました。

class MyTestCase extends PHPUnit_Framework_TestCase
{
    public static function assertArraysSame($expected, $actual, array $ignoreKeys = array())
    {
        self::doAssertArraysSame($expected, $actual, $ignoreKeys, 1);
    }

    private static function doAssertArraysSame($expected, $actual, array $ignoreKeys = array(), $depth, $maxDepth = 256)
    {
        self::assertNotEquals($depth, $maxDepth);
        $depth++;

        foreach ($expected as $key => $exp) {
            // check they both have this key
            self::assertArrayHasKey($key, $actual);

            // check nested arrays 
            if (is_array($exp))
                self::doAssertArraysSame($exp, $actual[$key], $ignoreKeys, $depth);

            // check they have the same value unless the key is in the to-ignore list
            else if (array_search($key, $ignoreKeys) === false)
                self::assertSame($exp, $actual[$key]);

            // remove the current elements
            unset($expected[$key]);
            unset($actual[$key]);
        }

        // check that the two arrays are both empty now, which means they had the same lenght
        self::assertEmpty($expected);
        self::assertEmpty($actual);
    }
}

doAssertArraysSame配列の 1 つを反復処理し、2 つの配列が同じキーを持つことを再帰的にアサートします。また、現在のキーが無視するキーのリストにない限り、それらの値が同じであることも確認します。

2 つの配列の要素数が正確に同じであることを確認するために、反復中に各要素が削除され、ループの最後に、関数は両方の配列が空であることを確認します。

使用法:

class MyTest extends MyTestCase
{
    public function test_Books()
    {
        $a1 = array('id' => 1, 'title' => 'the title');
        $a2 = array('id' => 2, 'title' => 'the title');

        self::assertArraysSame($a1, $a2, array('id'));
    }
}

私の質問は、おそらく既に利用可能な PHP/PHPUnit 関数を使用して、このタスクを達成するためのより良い方法または簡単な方法はありますか?

編集: PHPUnit のソリューションが必ずしも必要ではないことに注意してください。これを実行できるプレーンな PHP 関数があれば、テストで使用できます。

4

2 に答える 2

5

これがあなたがすでに使用しているものよりも優れた解決策であるかどうかはわかりませんが、私がこの正確な必要性を持っていたとき、私は以前に同様のクラスを使用しました。それはあなたに単純な真または偽の応答を与えることができ、テストフレームワークに結合されていません。それはあなたにとって良いことかもしれないし、そうでないかもしれません。

class RecursiveArrayCompare
{
    /**
     * @var array
     */
    protected $ignoredKeys;

    /**
     *
     */
    function __construct()
    {
        $this->ignoredKeys = array();
    }

    /**
     * @param array $ignoredKeys
     * @return RecursiveArrayCompare
     */
    public function setIgnoredKeys(array $ignoredKeys)
    {
        $this->ignoredKeys = $ignoredKeys;

        return $this;
    }

    /**
     * @param array $a
     * @param array $b
     * @return bool
     */
    public function compare(array $a, array $b)
    {
        foreach ($a as $key => $value) {
            if (in_array($key, $this->ignoredKeys)) {
                continue;
            }

            if (!array_key_exists($key, $b)) {
                return false;
            }

            if (is_array($value) && !empty($value)) {
                if (!is_array($b[$key])) {
                    return false;
                }

                if (!$this->compare($value, $b[$key])) {
                    return false;
                }
            } else {
                if ($value !== $b[$key]) {
                    return false;
                }
            }

            unset($b[$key]);
        }

        $diff = array_diff(array_keys($b), $this->ignoredKeys);

        return empty($diff);
    }
}

そして、提供された配列に基づくいくつかの例:

$arr1 = array(
    'id' => 0,
    'title' => 'Book1 title',
    'creationDate' => '2013-01-13 17:01:07',
    'pageCount' => 0
);

// only difference is value of ignored key
$arr2 = array(
    'id' => 1,
    'title' => 'Book1 title',
    'creationDate' => '2013-01-13 17:01:07',
    'pageCount' => 0
);

// has extra key
$arr3 = array(
    'id' => 1,
    'title' => 'Book1 title',
    'creationDate' => '2013-01-13 17:01:07',
    'pageCount' => 0,
    'extra_key' => 1
);

// has extra key, which is ignored
$arr4 = array(
    'id' => 1,
    'title' => 'Book1 title',
    'creationDate' => '2013-01-13 17:01:07',
    'pageCount' => 0,
    'ignored_key' => 1
);

// has different value
$arr5 = array(
    'id' => 2,
    'title' => 'Book2 title',
    'creationDate' => '2013-01-13 17:01:07',
    'pageCount' => 0
);

$comparer = new RecursiveArrayCompare();
$comparer->setIgnoredKeys(array('id', 'ignored_key'));

var_dump($comparer->compare($arr1, $arr2)); // true
var_dump($comparer->compare($arr1, $arr3)); // false
var_dump($comparer->compare($arr1, $arr4)); // true
var_dump($comparer->compare($arr1, $arr5)); // false

編集

このような別のクラスを使用する利点は、このクラスを単体テストして、期待どおりに動作することを確認するのも簡単なことです。ツールが正しく機能していることを保証できない場合は、テストにツールを使用する必要はありません。

于 2013-01-15T11:06:19.897 に答える
0

配列要素をforeachできます

foreach ($array1 as $index => $subArray)
{
    $this->assertEquals($array1[$index]['title'], $array2[$index]['title');
    $this->assertEquals($array1[$index]['creationDate'], $array2[$index]['creationDate');
    $this->assertEquals($array1[$index]['pageCount'], $array2[$index]['pageCount');
}   
于 2013-01-15T16:24:36.803 に答える