[php] PHPUnit : 두 배열이 같다고 주장하지만 요소의 순서는 중요하지 않습니다.

배열의 요소 순서가 중요하지 않거나 변경 될 수있는 경우 두 배열의 객체가 동일하다고 주장하는 좋은 방법은 무엇입니까?



답변

가장 깨끗한 방법은 새로운 어설 션 방법으로 phpunit을 확장하는 것입니다. 그러나 지금은 더 간단한 방법에 대한 아이디어가 있습니다. 테스트되지 않은 코드는 다음을 확인하십시오.

앱 어딘가에 :

 /**
 * Determine if two associative arrays are similar
 *
 * Both arrays must have the same indexes with identical values
 * without respect to key ordering
 *
 * @param array $a
 * @param array $b
 * @return bool
 */
function arrays_are_similar($a, $b) {
  // if the indexes don't match, return immediately
  if (count(array_diff_assoc($a, $b))) {
    return false;
  }
  // we know that the indexes, but maybe not values, match.
  // compare the values between the two arrays
  foreach($a as $k => $v) {
    if ($v !== $b[$k]) {
      return false;
    }
  }
  // we have identical indexes, and no unequal values
  return true;
}

테스트에서 :

$this->assertTrue(arrays_are_similar($foo, $bar));


답변

assertEqualsCanonicalizing 을 사용할 수 있습니다PHPUnit 7.5에 추가 된 메소드를 . 이 방법을 사용하여 배열을 비교하면 이러한 배열은 PHPUnit 배열 비교기 자체에 따라 정렬됩니다.

코드 예 :

class ArraysTest extends \PHPUnit\Framework\TestCase
{
    public function testEquality()
    {
        $obj1 = $this->getObject(1);
        $obj2 = $this->getObject(2);
        $obj3 = $this->getObject(3);

        $array1 = [$obj1, $obj2, $obj3];
        $array2 = [$obj2, $obj1, $obj3];

        // Pass
        $this->assertEqualsCanonicalizing($array1, $array2);

        // Fail
        $this->assertEquals($array1, $array2);
    }

    private function getObject($value)
    {
        $result = new \stdClass();
        $result->property = $value;
        return $result;
    }
}

이전 버전의 PHPUnit에서는 문서화되지 않은 매개 변수 $ canonicalize of assertEquals 메소드를 사용할 수 있습니다 . $ canonicalize = true 를 전달 하면 동일한 효과가 나타납니다.

class ArraysTest extends PHPUnit_Framework_TestCase
{
    public function testEquality()
    {
        $obj1 = $this->getObject(1);
        $obj2 = $this->getObject(2);
        $obj3 = $this->getObject(3);

        $array1 = [$obj1, $obj2, $obj3];
        $array2 = [$obj2, $obj1, $obj3];

        // Pass
        $this->assertEquals($array1, $array2, "\$canonicalize = true", 0.0, 10, true);

        // Fail
        $this->assertEquals($array1, $array2, "Default behaviour");
    }

    private function getObject($value)
    {
        $result = new stdclass();
        $result->property = $value;
        return $result;
    }
}

최신 버전의 PHPUnit에서 배열 비교기 소스 코드 : https://github.com/sebastianbergmann/comparator/blob/master/src/ArrayComparator.php#L46


답변

내 문제는 내가 2 개의 배열을 가지고 있다는 것입니다 (배열 키는 나와 관련이 없으며 값만 있습니다).

예를 들어

$expected = array("0" => "green", "2" => "red", "5" => "blue", "9" => "pink");

같은 내용 (나와 관련이없는 순서)을 가졌습니다

$actual = array("0" => "pink", "1" => "green", "3" => "yellow", "red", "blue");

그래서 array_diff 사용했습니다 .

최종 결과는 (배열이 같으면 차이가 빈 배열이 됨)입니다. 차이는 두 가지 방식으로 계산됩니다 (감사합니다 @beret, @GordonM).

$this->assertEmpty(array_merge(array_diff($expected, $actual), array_diff($actual, $expected)));

더 자세한 오류 메시지 (디버깅 중)를 보려면 다음과 같이 테스트 할 수도 있습니다 (@ DenilsonSá 덕분에).

$this->assertSame(array_diff($expected, $actual), array_diff($actual, $expected));

내부 버그가있는 이전 버전 :

$ this-> assertEmpty (array_diff ($ array2, $ array1));


답변

다른 가능성 :

  1. 두 배열 모두 정렬
  2. 문자열로 변환
  3. 두 문자열이 동일하다고 가정

$arr = array(23, 42, 108);
$exp = array(42, 23, 108);

sort($arr);
sort($exp);

$this->assertEquals(json_encode($exp), json_encode($arr));


답변

간단한 도우미 방법

protected function assertEqualsArrays($expected, $actual, $message) {
    $this->assertTrue(count($expected) == count(array_intersect($expected, $actual)), $message);
}

또는 배열이 같지 않을 때 더 많은 디버그 정보가 필요한 경우

protected function assertEqualsArrays($expected, $actual, $message) {
    sort($expected);
    sort($actual);

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


답변

배열을 정렬 할 수 있으면 동등성을 확인하기 전에 둘 다 정렬합니다. 그렇지 않다면, 그것들을 일종의 세트로 변환하고 비교할 것입니다.


답변

사용 ) (array_diff를 :

$a1 = array(1, 2, 3);
$a2 = array(3, 2, 1);

// error when arrays don't have the same elements (order doesn't matter):
$this->assertEquals(0, count(array_diff($a1, $a2)) + count(array_diff($a2, $a1)));

또는 두 가지 주장 (읽기 쉬움) :

// error when arrays don't have the same elements (order doesn't matter):
$this->assertEquals(0, count(array_diff($a1, $a2)));
$this->assertEquals(0, count(array_diff($a2, $a1)));