অ্যারেতে থাকা উপাদানগুলির ক্রম গুরুত্বহীন বা এমনকি পরিবর্তনের সাপেক্ষে যখন দুটি অ্যারের অবজেক্ট সমান হয় তা জোর দিয়ে দেওয়ার একটি ভাল উপায় কী?
অ্যারেতে থাকা উপাদানগুলির ক্রম গুরুত্বহীন বা এমনকি পরিবর্তনের সাপেক্ষে যখন দুটি অ্যারের অবজেক্ট সমান হয় তা জোর দিয়ে দেওয়ার একটি ভাল উপায় কী?
উত্তর:
এটি করার সর্বোত্তম উপায় হ'ল কোনও নতুন আসক্তি পদ্ধতি সহ 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));
count(array_diff_assoc($b, $a))
।
আপনি assertEqualsCanonicalization পদ্ধতিটি ব্যবহার করতে পারেন যা পিএইচপিউনিট 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;
}
}
পিএইচপিউইন্টের পুরানো সংস্করণগুলিতে আপনি একটি নির্বিঘ্নিত পরম ব্যবহার করতে পারেন $ assertEquals পদ্ধতির canonicalize । আপনি যদি $ canonicalize = সত্যটি পাস করেন তবে আপনি একই প্রভাব পাবেন:
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
পরামিতিগুলি ব্যবহার করা বিভ্রান্তিমূলক - পিএইচপি নামযুক্ত যুক্তি সমর্থন করে না। এটি আসলে যা করছে তা হ'ল তিনটি ভেরিয়েবল সেট করা, তারপরে তত্ক্ষণাত তাদের মানগুলি ফাংশনে প্রেরণ করা। যদি এই তিনটি ভেরিয়েবলগুলি স্থানীয় স্কোপে ইতিমধ্যে সংজ্ঞায়িত করা হয় তবে সেগুলি ওভাররাইট হবে।
$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");
সুতরাং আমি অ্যারে_ডিফ ব্যবহার করেছি ।
চূড়ান্ত ফলাফলটি ছিল (যদি অ্যারেগুলি সমান হয় তবে পার্থক্যটি খালি অ্যারে তৈরি করবে)। দয়া করে মনে রাখবেন যে পার্থক্যটি উভয় উপায়ে গণনা করা হয়েছে (ধন্যবাদ @ বারেট, @ গর্ডনএম)
$this->assertEmpty(array_merge(array_diff($expected, $actual), array_diff($actual, $expected)));
আরও বিশদ ত্রুটির বার্তার জন্য (ডিবাগ করার সময়) আপনিও এটি পরীক্ষা করতে পারেন (ধন্যবাদ @ ডেনিলসনá):
$this->assertSame(array_diff($expected, $actual), array_diff($actual, $expected));
ভিতরে বাগ সহ পুরানো সংস্করণ:
$ এটি-> assertEmpty (অ্যারে_ডিফ ($ অ্যারে 2, $ অ্যারে 1));
$array1
এর চেয়ে বেশি মান থাকে $array2
তবে অ্যারের মান সমান না হলেও এটি খালি অ্যারে প্রদান করে। আপনারও পরীক্ষা করা উচিত, নিশ্চিত হওয়ার জন্য যে অ্যারের আকার একই is
$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 = 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);
}
অ্যারেটি বাছাইযোগ্য হলে সাম্যতা যাচাই করার আগে আমি তাদের উভয়কে বাছাই করব। যদি তা না হয় তবে আমি তাদের কোনও ধরণের সেটগুলিতে রূপান্তর করব এবং সেগুলির সাথে তুলনা করব।
অ্যারে_ডিফ () ব্যবহার করে :
$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);
এইভাবে আপনি স্বাধীন অর্ডার করছেন তবে এখনও দৃ still়ভাবে বলুন যে আপনার সমস্ত উপাদান উপস্থিত রয়েছে।
assertArraySubset
ইনডেক্স ক্রম তাই কোন ব্যাপার এটা কাজ করবে না। অর্থাৎ স্ব :: :: assertArraySubset (['a'], ['বি', 'a']) মিথ্যা হবে, কারণ [0 => 'a']
এটি ভিতরে নেই[0 => 'b', 1 => 'a']
assertEquals
ইতিমধ্যে হ্যান্ডলগুলি হয় যে কীগুলি একই ক্রমে না থাকলে। আমি ঠিক এটি পরীক্ষা করেছি।