PHPUnit 7 から PHPUnit 8 へアップデートしたら、次のWarning が表示されました。
assertArraySubset() is deprecated and will be removed in PHPUnit 9.
Code language: plaintext (plaintext)
おー、なんてこと!
PHPUnit 9 で assertArraySubset は廃止されてしまうんですね...
修正前
$actual = 大きめの配列
$expected = [
'Summary' => [
'error_code' => '00001',
'error_message' => 'パラメータに誤りがあります',
'summary_id' => 1,
],
'Details' => [
[
'error_codes' => '0001 0002',
'summary_id' => 1,
'detail_id' => 1,
],
[
'error_codes' => '0003 0004',
'summary_id' => 1,
'detail_id' => 2,
],
],
];
$this->assertArraySubset($expected, $actual);
Code language: PHP (php)
案1
まず試したのは、配列要素を一つづつ assertEquals で比較する方法です。
$this->assertEquals('0001', $actual['Summary']['error_code']);
$this->assertEquals('パラメータに誤りがあります', $actual['Summary']['error_message']);
$this->assertEquals(1, $actual['Summary']['summary_id']);
$this->assertEquals('0001 0002', $actual['Details'][0]['error_codes']);
$this->assertEquals(1, $actual['Details'][0]['summary_id']);
$this->assertEquals(1, $actual['Details'][0]['detail_id']);
$this->assertEquals('0003 0004', $actual['Details'][1]['error_codes']);
$this->assertEquals(1, $actual['Details'][1]['summary_id']);
$this->assertEquals(2, $actual['Details'][1]['detail_id']);
Code language: PHP (php)
んー、読みにくいですね。assertEquals が大量に並んでいると読む気がしないですね。
$actual がどんな構造なのかピンとこないですし。
例えば、L10 を次のようにタイポしていても気づきにくいです。
$this->assertEquals(1, $actual['Details'][0]['summary_id']);
Code language: PHP (php)
これはボツにしたいですね。
案2
assertArraySubset だけでPHPUnitとは別でパッケージ公開されています。
sebastianbergmann(PHPUnitのオーナー)が言っていたように、assertArraySubset のコードを別パッケージにしたぜ
https://github.com/sebastianbergmann/phpunit/issues/3494#issuecomment-464464423
composer でパッケージインストールし、
composer require --dev dms/phpunit-arraysubset-asserts
Code language: JavaScript (javascript)
テストに次の2行を挿入します。
use DMS\PHPUnitExtensions\ArraySubset\ArraySubsetAsserts; // ★コレ
class ExampleTest extends TestCase
{
use ArraySubsetAsserts; // ★コレ
Code language: PHP (php)
すると、$this->assertArraySubset は変更することなく使えます。
これがいいかなと思ったんですが、なぜ assertArraySubset を廃止にすることになったのか気になったので、もう少し調べると...
assertArraySubset はアサーションに失敗したときのメッセージが不親切なんですね。
配列全体を表示するので、どこが違ったのかがわからず、あらためて調べなければならないんです。
この表示を改善してほしいという issue が上がっていたようですが...
sebastianbergmann が出した答えが
下位互換性を維持したまま、この表示を改善することはできないという結論に達した
https://github.com/sebastianbergmann/phpunit/issues/3494#issue-401764930
「assertArraySubset はアサーションに失敗したときのメッセージが不親切」たしかにこれは問題ですね
案3
配列の要素を一つづつ assertEquals で検証するのではなく、$expected の構造のデータを作って、$expected と assertEquals するようにしました。
$actual = 大きめの配列
$expected = [
'Summary' => [
'error_code' => '00001',
'error_message' => 'パラメータに誤りがあります',
'summary_id' => 1,
],
'Details' => [
[
'error_codes' => '0001 0002',
'summary_id' => 1,
'detail_id' => 1,
],
[
'error_codes' => '0003 0004',
'summary_id' => 1,
'detail_id' => 2,
],
],
];
$actualSubset = [
'Summary' => [
'error_code' => $actual['Summary']['error_code'],
'error_message' => $actual['Summary']['error_message'],
'summary_id' => $actual['Summary']['summary_id'],
],
'Details' => [
[
'error_codes' => $actual['Details'][0]['error_codes'],
'sumamry_id' => $actual['Details'][0]['summary_id'],
'detail_id' => $actual['Details'][0]['detail_id'],
],
[
'error_codes' => $actual['Details'][1]['error_codes'],
'sumamry_id' => $actual['Details'][1]['summary_id'],
'detail_id' => $actual['Details'][1]['detail_id'],
],
],
];
$this->assertEquals($expected, $actualSubset);
Code language: PHP (php)
失敗したときのメッセージ(推測)
-- Expected
+++ Actual
@@ @@
Array (
'Summary' => Array (
- 'error_code' => '00001'
+ 'error_code' => '00002'
'error_message' => '英数字以外を含みます'
'id' => 1
)
'Details' => Array (...)
)
Code language: plaintext (plaintext)
テストコードは長くなりましたが、案1 より読みやすくなりました。
そして、失敗メッセージを見るだけで、どの要素で失敗したのかがわかるようになりました。