वस्तुओं के दो सरणियों के बराबर होने का दावा करने का एक अच्छा तरीका क्या है, जब सरणी में तत्वों का क्रम महत्वहीन है, या यहां तक कि परिवर्तन के अधीन है?
वस्तुओं के दो सरणियों के बराबर होने का दावा करने का एक अच्छा तरीका क्या है, जब सरणी में तत्वों का क्रम महत्वहीन है, या यहां तक कि परिवर्तन के अधीन है?
जवाबों:
ऐसा करने का सबसे साफ तरीका यह होगा कि एक नए दावे के साथ फ़ापुनिट का विस्तार किया जाए। लेकिन अब के लिए एक सरल तरीके के लिए यहां एक विचार है। अयोग्य कोड, कृपया सत्यापित करें:
आपके ऐप में कहीं:
/**
* 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));
count(array_diff_assoc($b, $a))
भी आवश्यकता है ।
आप 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 के पुराने संस्करणों में आप एक अपरिवर्तित परम $ asonorquals विधि के कैनोनिकलाइज़ का उपयोग कर सकते हैं । यदि आप $ 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
$delta = 0.0, $maxDepth = 10, $canonicalize = true
फ़ंक्शन में मापदंडों को पारित करने के लिए उपयोग करना भ्रामक है - PHP नाम के तर्कों का समर्थन नहीं करता है। यह वास्तव में क्या कर रहा है उन तीन चर को सेट कर रहा है, फिर तुरंत अपने मूल्यों को फ़ंक्शन में पास कर रहा है। यह समस्याएँ पैदा करेगा यदि उन तीन चर को पहले से ही स्थानीय दायरे में परिभाषित किया गया है क्योंकि वे अधिलेखित हो जाएंगे।
$this->assertEquals($array1, $array2, "\$canonicalize = true", 0.0, 10, true);
:। मैं 1 के बजाय 4 लाइनों का उपयोग कर सकता था, लेकिन मैंने ऐसा नहीं किया।
$canonicalize
हटा दिया जाएगा: github.com/sebastianbergmann/phpunit/issues/3342 और assertEqualsCanonicalizing()
इसे बदल देगा।
मेरी समस्या यह थी कि मेरे पास 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));
अंदर कीड़े के साथ पुराना संस्करण:
$ यह-> assertEmpty (array_diff ($ array2, $ array1));
$array1
इससे अधिक मान हैं $array2
, तो यह खाली सरणी देता है , भले ही सरणी मान समान न हो। आपको यह भी परखना चाहिए, कि सरणी का आकार समान है, सुनिश्चित करने के लिए।
$a1 = [1,2,3,4,5]; $a2 = [1,3,5]; var_dump (array_diff ($a1, $a2)); var_dump (array_diff ($a2, $a1))
assertEmpty
खाली न होने पर सरणी को प्रिंट नहीं करेंगे, जो कि डिबगिंग परीक्षणों के दौरान असुविधाजनक है। मैं उपयोग करने का सुझाव देता हूं: $this->assertSame(array_diff($expected, $actual), array_diff($actual, $expected), $message);
क्योंकि यह अतिरिक्त कोड के न्यूनतम के साथ सबसे उपयोगी त्रुटि संदेश को प्रिंट करेगा। यह काम करता है क्योंकि A \ B = B \ A ⇔ A \ B और B \ A खाली हैं A A = B
Array to string conversion
जब आप किसी स्ट्रिंग को एक सरणी देने का प्रयास करेंगे तो आपको एक संदेश मिलेगा । इसके आसपास जाने का एक तरीका हैimplode
एक अन्य संभावना:
$arr = array(23, 42, 108);
$exp = array(42, 23, 108);
sort($arr);
sort($exp);
$this->assertEquals(json_encode($exp), json_encode($arr));
assertEquals
आदेश के लिए कोई फर्क नहीं पड़ता।
$this->assertSame($exp, $arr);
जो समान तुलना करता है क्योंकि $this->assertEquals(json_encode($exp), json_encode($arr));
केवल अंतर यह है कि हमें json_encode का उपयोग करने की आवश्यकता नहीं है
सरल सहायक विधि
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)));
या 2 जोर के साथ (पढ़ने में आसान):
// 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)));
भले ही आप आदेश के बारे में परवाह नहीं करते हैं, लेकिन इसे ध्यान में रखना आसान हो सकता है:
प्रयत्न:
asort($foo);
asort($bar);
$this->assertEquals($foo, $bar);
हम अपने टेस्ट में निम्नलिखित आवरण विधि का उपयोग करते हैं:
/**
* Assert that two arrays are equal. This helper method will sort the two arrays before comparing them if
* necessary. This only works for one-dimensional arrays, if you need multi-dimension support, you will
* have to iterate through the dimensions yourself.
* @param array $expected the expected array
* @param array $actual the actual array
* @param bool $regard_order whether or not array elements may appear in any order, default is false
* @param bool $check_keys whether or not to check the keys in an associative array
*/
protected function assertArraysEqual(array $expected, array $actual, $regard_order = false, $check_keys = true) {
// check length first
$this->assertEquals(count($expected), count($actual), 'Failed to assert that two arrays have the same length.');
// sort arrays if order is irrelevant
if (!$regard_order) {
if ($check_keys) {
$this->assertTrue(ksort($expected), 'Failed to sort array.');
$this->assertTrue(ksort($actual), 'Failed to sort array.');
} else {
$this->assertTrue(sort($expected), 'Failed to sort array.');
$this->assertTrue(sort($actual), 'Failed to sort array.');
}
}
$this->assertEquals($expected, $actual);
}
यदि कुंजियाँ समान हैं लेकिन क्रम से बाहर हैं तो इसे हल करना चाहिए।
आपको बस उसी क्रम में कुंजियाँ प्राप्त करनी हैं और परिणामों की तुलना करनी है।
/**
* Assert Array structures are the same
*
* @param array $expected Expected Array
* @param array $actual Actual Array
* @param string|null $msg Message to output on failure
*
* @return bool
*/
public function assertArrayStructure($expected, $actual, $msg = '') {
ksort($expected);
ksort($actual);
$this->assertSame($expected, $actual, $msg);
}
दिए गए समाधानों ने मेरे लिए काम नहीं किया क्योंकि मैं बहुआयामी सरणी को संभालने में सक्षम होना चाहता था और दो सरणियों के बीच क्या अलग है इसका स्पष्ट संदेश देना चाहता था।
यहाँ मेरा कार्य है
public function assertArrayEquals($array1, $array2, $rootPath = array())
{
foreach ($array1 as $key => $value)
{
$this->assertArrayHasKey($key, $array2);
if (isset($array2[$key]))
{
$keyPath = $rootPath;
$keyPath[] = $key;
if (is_array($value))
{
$this->assertArrayEquals($value, $array2[$key], $keyPath);
}
else
{
$this->assertEquals($value, $array2[$key], "Failed asserting that `".$array2[$key]."` matches expected `$value` for path `".implode(" > ", $keyPath)."`.");
}
}
}
}
फिर इसका उपयोग करने के लिए
$this->assertArrayEquals($array1, $array2, array("/"));
मैंने पहले बहु-आयामी सरणी से सभी कुंजी प्राप्त करने के लिए कुछ सरल कोड लिखे:
/**
* Returns all keys from arrays with any number of levels
* @param array
* @return array
*/
protected function getAllArrayKeys($array)
{
$keys = array();
foreach ($array as $key => $element) {
$keys[] = $key;
if (is_array($array[$key])) {
$keys = array_merge($keys, $this->getAllArrayKeys($array[$key]));
}
}
return $keys;
}
फिर यह परीक्षण करने के लिए कि उन्हें चाबियों के क्रम की परवाह किए बिना संरचित किया गया था:
$expectedKeys = $this->getAllArrayKeys($expectedData);
$actualKeys = $this->getAllArrayKeys($actualData);
$this->assertEmpty(array_diff($expectedKeys, $actualKeys));
HTH
यदि मान केवल इंट या स्ट्रिंग्स हैं, और कोई भी एकाधिक स्तरीय सरणियाँ नहीं हैं ...।
क्यों न केवल सरणियों को छाँटकर, उन्हें स्ट्रिंग में परिवर्तित करें ...
$mapping = implode(',', array_sort($myArray));
$list = implode(',', array_sort($myExpectedArray));
... और फिर स्ट्रिंग की तुलना करें:
$this->assertEquals($myExpectedArray, $myArray);
यदि आप केवल उस सरणी के मानों का परीक्षण करना चाहते हैं जो आप कर सकते हैं:
$this->assertEquals(array_values($arrayOne), array_values($arrayTwo));
echo("<pre>"); print_r(array_values(array("size" => "XL", "color" => "gold"))); print_r(array_values(array("color" => "gold", "size" => "XL")));
एक अन्य विकल्प, जैसे कि आपके पास पहले से ही पर्याप्त नहीं था, assertArraySubset
संयुक्त रूप से assertCount
अपना दावा करने के लिए संयुक्त है । तो, आपका कोड कुछ ऐसा दिखाई देगा।
self::assertCount(EXPECTED_NUM_ELEMENT, $array);
self::assertArraySubset(SUBSET, $array);
इस तरह से आप स्वतंत्र हैं लेकिन फिर भी यह दावा करते हैं कि आपके सभी तत्व मौजूद हैं।
assertArraySubset
इंडेक्सों का आदेश तो कोई फर्क यह काम नहीं करेगा। अर्थात स्व :: assertArraySubset (['a'], [, b ',' a ’) झूठा होगा, क्योंकि [0 => 'a']
अंदर नहीं है[0 => 'b', 1 => 'a']
assertEquals
पहले से ही संभालता है कि यदि चाबियाँ समान क्रम में नहीं हैं। मैंने अभी इसका परीक्षण किया।