1. Perl
  2. Exam

Test::More - Write a test program for automated testing

Almost every Perl module on CPAN comes with a program to test your program. Not only the program, but also the program for testing the program comes with it. This is called an automatic test. Instead of running each program by hand, you can just run the automated test program and see if it works properly.

In Perl, it's convenient to write automated test programs using the standard module Test::More . Here, we will explain the advantages of automated tests and how to write automated tests with Test::More.

Advantages of automated testing

1. Regression test can be done easily.

The regression test, also known as the regression test, is a test that confirms that the original function works properly when a function is added to the program. Once you have created an automated test, you only have to make sure that the automated test succeeds after you add functionality to your program.

2. Can be refactored

Refactoring is about cleaning up your code. The act of rewriting the code to improve versatility and readability. It is not good to leave a dirty code. For programs that need to adapt to change, you need to code to make it easier to add features.

Creating an automated test allows you to refactor without compromising functionality.

Notes on automatic testing

1. I don't know whether the code itself is good or bad.

An automated test is a test to see the function. I can't tell if the code is versatile, if it's neatly organized into subroutine, or if it's highly readable. I think it would be better to combine it with inspection, code reading, etc.

2. Visual check is also performed

Automatic exams are not perfect exams. There will be a mistake in writing the automatic test. It is also possible that the automatic test was not conducted due to a misunderstanding, or that the test itself was wrong.

The key to eliminating test mistakes is to test from as many perspectives as possible. Therefore, when writing an automated test, it is recommended that you use a debugger to check the actual movement in parallel. Make sure that the inside of the program is working as intended.

Once you have written the correct exam, you can check it automatically.

Simple example of automatic test

Now let's write an automated test program using Perl's module for automated tests Test::More.

use strict;
use warnings;

# Specify the number of tests
use Test::More tests => 2;

# Check if the test was successful with the ok function. This test succeeds.
my $num1 = 1;
ok ($num1 == 1);

# This exam fails
my $num2 = 2;
ok ($num2 == 1);

A description of the automated test script.

1. Specify the number of exams.

When using Test::More, specify the number of tests.

use Test::More tests => 2;

2. Check the test result with the ok function

The first argument of the ok function describes the conditions under which the test will succeed.

# Check if the test was successful with the ok function. This test succeeds.
my $num1 = 1;
ok ($num1 == 1);

# This exam fails
my $num2 = 2;
ok ($num2 == 1);

This statement can be read as "If $num1 is equal to 1, the test is successful" and "If $num2 is equal to 1, the test is successful".

3. Test results

The test results of the above example are as follows. You can see that the first exam was successful and the second exam was unsuccessful.

1..2
ok 1 - Test1
not ok 2 - Test2
# Failed test'Test2'
# at b.pl line 9.
# Looks like you failed 1 test of 2.

Test subroutine

Let's take a look at another simple example. Test a function called sum that sums two numbers and a function called double that doubles the numbers. The double function is supposed to be doubled, but it is mistakenly tripled so that the automated test fails.

use strict;
use warnings;

use Test::More tests => 2;


# Collision of a lexical variable declared by my does not occur when creating a scope in test units.
# sum exam
{
  my $num1 = 1;
  my $num2 = 2;
  
  my $total = sum ($num1, $num2);
  
  ok ($total == 3, 'sum');
}

# double exam
{
  my $num1 = 1;
  
  my $double = double ($num1);
    
  # Failure!
  ok ($double == 2, 'double');
}

# Subroutine that sums two numbers
sub sum {
  my ($num1, $num2) = @_;
  return $num1 + $num2;
}

# Subroutine that doubles the number
sub double {
  my $num = shift;

  # I had to double it, but I accidentally tripled it!
  return $num * 3
}

1. Automatic subroutine test

Performs an automatic test for each subroutine. In this example, we are testing a subroutine called sum.

{
  my $num1 = 1;
  my $num2 = 2;
  
  my $total = sum ($num1, $num2);
  
  ok ($total == 3, 'sum');
}

# Subroutine that sums two numbers
sub sum {
  my ($num1, $num2) = @_;
  return $num1 + $num2;
}

2. Create a scope for each test unit.

As you write a lot of tests, variable name collisions become more frequent. To avoid this, create a scope with {} and write each test in it.

# sum exam
{
  my $num1 = 1;
  my $num2 = 2;
  
  my $total = sum ($num1, $num2);
  
  ok ($total == 3, 'sum');
}

# double exam
{
  my $num1 = 1;
  
  my $double = double ($num1);
  
  ok ($double == 2, 'double'); # Failed!
}

3. Test results

Let's take a look at the test results. The double function is wrongly a function that triples, so the second test fails.

ok 1 - sum
not ok 2 - double
# Failed test'double'
# at - line 25.
# Looks like you failed 1 test of 2.

Automatic test layout

The above script was done in one file, but I'll show you the general layout of the automated test directory. The layout of the automated test directory is as follows. Suppose you want to test a module called SomeModule.pm.

SomeModule/    |
    | - -- lib/    | |
    | | - -- SomeModule.pm
    |
    |
    | - --- t/           |
           | - -- sum.t
           |
           | - -- double.t

The module itself is stored in a directory called lib. The automated test program is stored in a directory named t. The extension of the automated test program should be .t.

There are no absolute rules for the layout, but many modules that make Perl's automated testing useful assume this layout, so let's do it.

Module example

This is an example module for testing. Save it as "SomeModule.pm" and store it in "lib".

package SomeModule;
use strict;
use warnings;

# A function that sums two numbers
sub sum {
  my ($num1, $num2) = @_;
  return $num1 + $num2;
}

# Subroutine that doubles the number
sub double {
  my $num = shift;

  # I had to double it, but I accidentally tripled it!
  return $num * 3
}

1;

The last line of the module should return a true value. Be careful as it is easy to forget.

Test script

This is an example of automatic test.

sum.t

use strict;
use warnings;

# Add module search path
use FindBin;
use lib "$FindBin::Bin/../ lib";

use Test::More tests => 1;
use SomeModule;

# sum exam
{
my $num1 = 1;
  my $num2 = 2;
  
  my $total = SomeModule::sum ($num1, $num2);
  
  ok ($total == 3, 'sum');
}

(Reference) FindBin

double.t

use strict;
use warnings;

# Add module search path
use FindBin;
use lib "$FindBin::Bin/../ lib";

use Test::More tests => 1;
use SomeModule;

# double exam
{
  my $num1 = 1;
  
  my $double = SomeModule::double ($num1);
  
  ok ($double == 2, 'double');
}

Execution of automatic test

Let's run an automated test. To do an automated test, first go inside the Somo Module. Then run the following command:

perl t/sum.t

You can run the exam.

Run all automated tests with prove script

As the number of automated test programs increases, it is very troublesome to perform automated tests one by one. Perl has a handy script called prove that runs all the automated tests.

prove t

prove is very useful because it will perform all the automated tests for you.

The execution result of prove is as follows. You can see that the first test was successful and the second test was unsuccessful.

t\sum ....... ok
t\double ....
# t\double .... NOK 1/1 Failed test'double'
# at t\double.t line 13.
# Looks like you failed 1 test of 1.
t\double .... dubius
        Test returned status 1 (wstat 256, 0x100)
DIED. FAILED test 1
        Failed 1/1 tests, 0.00%okay
Failed Test Stat Wstat Total Fail List of Failed
- -- -- -- -- -- -- -- -- -- -- -- -- -- -- -- --- - -- -- -- -- -- -- -- -- -
t\double.t 1 256 1 1 1
Failed 1/2 test scripts. 1/2 subtests failed.
Files = 2, Tests = 2, 0 wallclock secs (0.00 cusr + 0.00 csys = 0.00 CPU)
Failed 1/2 test programs. 1/2 subtests failed.

The double function is wrong, so if you modify it to double the number, all the tests will succeed as below.

t\sum ....... ok
t\double .... ok
All tests successful.
Files = 2, Tests = 2, 0 wallclock secs (0.00 cusr + 0.00 csys = 0.00 CPU)

Test::More function

So far, we've used only the "ok function" to create tests, but the Test::More module has a lot of useful functions.

To test booleans, numbers, strings, object contents, etc., use the following functions.

function Commentary
is Make sure the strings are equal using eq. Numerical comparison of integers is still OK
isnt Use ne to make sure the strings are not equal. Numerical comparison of integers is still OK
like Make sure the string matches regular expression
unlike unlike Make sure the string doesn't match the regular expression
cmp_ok Compare by specifying Perl operators such as ==, <,>, <=, >= , gt, lt, etc.
is_deeply Used for comparing complex data structures such as arrays of arrays

is and isnt functions

The is function tests that the strings are equal. The isnt function tests that the strings are not equal.

is ($str, 3);
isnt ($str, 5);

The first argument is the value you want to test. The second argument is the expected result.

is and isnt use eq and ne, so they are compared as strings. (For example, "12.0" and 12 are different.) If you want to compare numbers and it's okay to compare them as strings, you can use is and isnt.

Otherwise, use a function called cmp_ok.

like and dislike functions

The like function tests that the string matches the regular expression. The dislike function tests that it doesn't match the regular expression .

like ($str, qr/\w+/);
unlike ($str, qr/\w+/);

The first argument is the value you want to test. The second argument is a regular expression reference .

Note that the second argument is a reference to the regular expression qr/\w+/. If you change this to'\w+'or/\w+/, the test will not work.

cmp_ok function

The cmp_ok function allows you to test using any comparison operator.

cmp_ok ($num, '<', 3);

The first and third arguments are the values you want to compare. The second argument is the comparison operator. All comparison operators such as "=", "<", "<=", " >= ", ">", "eq", "ne", "gt", "lt", "ge", and "le" can be used.

is_deeply function

You can use the is_deeply function to test complex data structures such as array reference and hash reference. This is very convenient.

is_deeply ($hash_ref, {a => 1, b => 2});

The first argument is the value you want to test. The second argument is the expected result.

Next, I will introduce a function for testing module loading, class definition, etc.

can_ok Check if the class has a method
isa_ok Check the class inherited by the object, check the reference type
require_ok Make sure the module can be required
use_ok Make sure the module can be used

can_ok function

The can_ok function is used for testing to make sure a class has a method.

can_ok ('Book', 'title', 'author', 'price', 'to_string', 'clone');

This is a test to make sure that the Book class has methods title, author, price, to_string, clone.

isa_ok function

isa_ok is used for testing to ensure that an object inherits a class.

my $comic = Comic->new;
isa_ok ($comic, 'Book');

This is a test to make sure that the $comic object inherits from the Book class.

The exam will also succeed if you specify its own class as follows:

isa_ok ($comic, 'Comic');

It also supports testing what kind of reference it is, not an object.

my $ary_ref = [];
isa_ok ($array_ref, 'ARRAY');

require_ok function

The require_ok function is used for testing to ensure that a module can be required.

require_ok ('Book');

This is a test to make sure the Book module can be required. It is a usage of require_ok, but it can be used when the module you want to distribute depends on another module, or when you want to confirm that the module exists.

use_ok function

The use_ok function is used for testing to check that the module can be used.

BEGIN {use_o

k ('Some::Module')}

FAQ

Is it possible to display easy - to - understand comments on the test results?

You can use the note function to display comments in your test results.

note'some test';

It's annoying to describe the number of exams

Use "no_plan" or "done_testing".

use Test::More 'no_plan';
use Test::More;

# Write an exam

done_testing;

Currently, done_testing is recommended.

In rare cases, there seems to be an edge case that passes even though the test has failed. If you want certainty, write the number of tests.

I want to skip some exams

For example, in certain environments you may want to skip the exam. Write as follows.

use Test::More;
if ($^O eq 'MacOS') {
  plan skip_all =>'Test irrelevant on MacOS';
}
else {
  plan tests => 42;
}

How do you test for exceptions?

If you want to see the exception occur, do the following:

# Confirm that an exception occurs
eval {some_func ()};
if ($@) {
  ok (1);
}
else {
  ok (0);
}

# Or check the error message
eval {some_func ()};
like ($@, qr/error /);

(Reference) eval

How do you test the warning?

If you want to see the warning, use a signal handler and do the following:

# Preparing to assign a warning message
my $warn;

# Handler called when a warning occurs
local $SIG{__ WARN__} = sub {
  $warn = shift;
};

$warn = undef;
some_func ();
if ($warn) {
  ok (1);
}
else {
  ok (0);
}

Finally

It is convenient to create an automated test using Test::More so that you can check whether the program is correct just by running the automated test. Also, in order to write its own CPAN module, you must remember it.

When I learned that the exam could be automated, I was struck by the fact that there was such a convenient way. Everyone, please use it conveniently.

Related Informatrion