Test:: More is_deeply не красиво печатает массив /hashrefs при сравнении со строками

Когда Test:: More сравнивается как arrayrefs и hashrefs друг с другом, соответствующее диагностическое сообщение действительно информативно и показывает первый индекс, где структуры отличаются, независимо от глубины вложенности. Однако, когда он сравнивает arrayref или hashref с простым скаляром, он создает строковый скаляр (с адресом памяти и ссылочным типом) в диагностическом сообщении, которое сложнее интерпретировать.

Есть ли способ настроить Test:: More для красивого массива или hashrefs настраиваемым способом (например, с использованием Data:: Dumper)?

Вот пример с двумя тестовыми примерами. Первое дает вам некоторое представление о том, что присутствует в вашей программе, но неожиданно. Второй информирует пользователя о несоответствии типа между строкой и arrayref, но не печатает какие-либо элементы в массивеref.

#!/usr/bin/env perl
use strict;
use warnings;
use Test::More tests => 2;

is_deeply(
    {
        a => [5],
    },
    {
        a => [5, 6, 8],
    },
    'compare two hashrefs structurally (very informative output)',
);

is_deeply(
    [5, 6, 8],
    "",
    'compare two "incompatible" values structurally (uninformative output)',
);

И вывод TAP:

1..2
not ok 1 - compare two hashrefs structurally (very informative output)
#   Failed test 'compare two hashrefs structurally (very informative output)'
#   at test-more-failure.pl line 6.
#     Structures begin differing at:
#          $got->{a}[1] = Does not exist
#     $expected->{a}[1] = '6'
not ok 2 - compare two "incompatible" values structurally (uninformative output)
#   Failed test 'compare two "incompatible" values structurally (uninformative output)'
#   at test-more-failure.pl line 16.
#     Structures begin differing at:
#          $got = ARRAY(0x7fe66b82cde8)
#     $expected = ''
# Looks like you failed 2 tests of 2.

Посмотрите на реализацию is_deeply в Test:: More, похоже, не существует способа использовать собственный симпатичный принтер или настроить многословие модуля. По крайней мере, мне это не кажется очевидным.

Вот что происходит, когда мы сравниваем ссылку и ссылку:

https://metacpan.org/source/EXODIST/Test-Simple-1.302062/lib/Test/More.pm#L1121

Кажется, он вызывает _format_stack({vals => [...]}) вместо _format_stack(...)

https://metacpan.org/source/EXODIST/Test-Simple-1.302062/lib/Test/More.pm#L1139

Ответ 1

tl; dr Используйте is_deeply($this, $that) || diag explain $this для каждого случая.

Привет. Я виноват в is_deeply. Это сознательно предназначено, чтобы не вырвать потенциально огромную структуру данных, когда что-то не удается. Вместо этого он останавливается при первой разнице. По этой причине вы, вероятно, не хотите глобально сделать is_deeply сброс своих аргументов. Если типы ошибочны, если вы ожидали яблок и получили зебры, не так много смысла в знании, сколько зебр и их жизненных историй.

Нет никакого поддерживаемого способа изменить свою диагностику, извините, и это вряд ли будет. Test:: More заменяется на Test2. Test:: More уже реализован поверх Test2, но не использует его возможности для обратной совместимости.

Вы можете использовать Test2::Bundle::More для более прямого доступа к функциям Test2, но он не на 100% совместим и отображает аналогично как is_deeply делает. Однако он намного более гибкий, и вы, вероятно, можете найти способ изменить его диагностическое поведение. Посмотрите Test2::Compare.


Вернитесь к своей проблеме... используйте explain в каждом отдельном случае. explain использует Data: Dumper, настроенный правильно, чтобы сбросить структуру данных. Так как Test:: More функции возвращают, прошли ли они или не удались, вы можете написать is_deeply($this, $that) || diag explain $this. Например...

my $stuff = [5, 6, 8];
is_deeply $stuff, "" || diag explain $stuff;

not ok 2
#   Failed test at /Users/schwern/tmp/test.plx line 17.
#     Structures begin differing at:
#          $got = ARRAY(0x7f80b3803078)
#     $expected = ''
# [
#   5,
#   6,
#   8
# ]

diag заключается в том, как вы печатаете диагностику отказа (это более вежливый способ печати в STDERR).

Ответ 2

Попробуйте eq_or_diff( $got, $expected, $message ) от Test::Differences, он напечатает красивое представление ваших структур данных и четко выделит точные сходства и различия.