简体   繁体   中英

Perl unit testing: check if a string is an array

I have this function that I want to test:

use constant NEXT => 'next';
use constant BACK => 'back';

sub getStringIDs {
    return [
        NEXT,
        BACK
    ];
}

I've tried to write the following test, but it fails:

subtest 'check if it contains BACK' => sub {
    use constant BACK => 'back';
    my $strings = $magicObject->getStringIDs();
    ok($strings =~ /BACK/);
}

What am I doing wrong?

The return value of $magicObject->getStringIDs is an array reference, not a string. It looks like the spirit of your test is that you want to check if at least one element in the array pattern matches BACK . The way to do this is to grep through the dereferenced array and check if there are a non-zero number of matches.

ok( grep(/BACK/,@$strings) != 0, 'contains BACK' );

At one time, the smartmatch operator promised to be a solution to this problem ...

ok( $strings ~~ /BACK/ )

but it has fallen into disrepute and should be used with caution (and the no warnings 'experimental::smartmatch' pragma).

Your getStringIDs() method returns an array reference.

The regex binding operator ( =~ ) expects a string on its left-hand side. So it converts your array reference to a string. And a stringified array reference will look something like ARRAY(0x1ff4a68) . It doesn't give you any of the contents of the array.

You can get from your array reference ( $strings ) to an array by dereferencing it ( @$strings ). And you can stringify an array by putting it in double quotes ( "@$strings" ).

So you could do something like this:

ok("@$strings" =~ /BACK/);

But I suspect, you want word boundary markers in there:

ok("@$strings" =~ /\bBACK\b/);

And you might also prefer the like() testing function.

like("@$strings", qr[\bBACK\b], 'Strings array contains BACK');

Update: Another alternative is to use grep to check that one of your array elements is the string "BACK".

# Note: grep in scalar context returns the number of elements
# for which the block evaluated as 'true'. If we don't care how
# many elements are "BACK", we can just check that return value
# for truth with ok(). If we care that it's exactly 1, we should
# use is(..., 1) instead.

ok(grep { $_ eq 'BACK' } @$strings, 'Strings array contains BACK');

Update 2: Hmm... the fact that you're using constants here complicates this. Constants are subroutines and regexes are strings and subroutines aren't interpolated in strings.

The in operator is your friend.

use Test::More;
use syntax 'in';

use constant NEXT => 'next';
use constant BACK => 'back';

ok BACK |in| [NEXT, BACK], 'BACK is in the arrayref';
done_testing;

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM