Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 32 additions & 0 deletions cpanfile
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# install required module dependancies listed here (runtime and test) with
# cpanm --installdeps .

on runtime => sub {
requires 'perl' => '5.20.3'; # guessing at a minimum viable version
recommends 'perl' => '5.30.0'; # needed for Statistics::R::IO

requires 'DBI';
requires 'Digest::MD5';
requires 'HTML::Entities';
requires 'JSON';
requires 'Tie::IxHash';
requires 'URI::Escape';
requires 'UUID::Tiny';
};

on test => sub {
requires 'HTML::TagParser'; # for t/macros/basicmacros.t
requires 'Test2::V0'; # for t/units/*

recommends 'Data::Dumper'; # for debugging data structures
recommends 'Test::Number::Delta'; # future unit tests using tolerance
recommends 'Test2::Tools::Explain'; # for debugging data structures
};

# install author dependancies with
# cpanm --installdeps --with-develop --with-recommends .

on develop => sub {
recommends 'Module::CPANfile';
recommends 'Test::CPANfile'; # verifies this file has all the dependancies
};
31 changes: 26 additions & 5 deletions lib/Units.pm
Original file line number Diff line number Diff line change
Expand Up @@ -475,9 +475,12 @@ our %known_units = ('m' => {
# cal -- calorie
# kcal -- kilocalorie
# eV -- electron volt
# keV -- kilo electron volt
# MeV -- mega electron volt
# GeV -- giga electron volt
# kWh -- kilo Watt hour
#
'J' => {
'J' => {
'factor' => 1,
'm' => 2,
'kg' => 1,
Expand All @@ -501,13 +504,13 @@ our %known_units = ('m' => {
'kg' => 1,
's' => -2
},
'kt' => {
'kt' => {
'factor' => 4.184E12,
'm' => 2,
'kg' => 1,
's' => -2
},
'Mt' => {
'Mt' => {
'factor' => 4.184E15,
'm' => 2,
'kg' => 1,
Expand All @@ -525,8 +528,26 @@ our %known_units = ('m' => {
'kg' => 1,
's' => -2
},
'eV' => {
'factor' => 1.60E-9,
'eV' => {
'factor' => 1.6022E-19,
'm' => 2,
'kg' => 1,
's' => -2
},
'keV' => {
'factor' => 1.6022E-16,
'm' => 2,
'kg' => 1,
's' => -2
},
'MeV' => {
'factor' => 1.6022E-13,
'm' => 2,
'kg' => 1,
's' => -2
},
'GeV' => {
'factor' => 1.6022E-10,
'm' => 2,
'kg' => 1,
's' => -2
Expand Down
14 changes: 0 additions & 14 deletions t/README

This file was deleted.

69 changes: 66 additions & 3 deletions t/README.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,45 @@
# Unit Tests for PG
# Testing PG

This directory houses the resources for testing PG. It includes a mix
of strategies for testing at different scales. It helps to catch errors
before they are found in production and prevent regressions from being
re-introduced.

The philosophy of
[Test Driven Design](https://en.wikipedia.org/wiki/Test-driven_development)
is that when a bug is found, a test is written to show it failing
and when it is fixed, the test will pass.
The unit tests are easy to run and amenable to automation. Some services
can be "mocked" so that behaviour can be tested in their absence.
All of this is to provide confidence that the code does what is intended
and a working test can be better than documentation because it shows how
the code currently works in practice.

Old references can be found on the WebWork wiki page
[Unit Testing](https://webwork.maa.org/wiki/Unit_Testing)


# Unit Tests

[Unit tests](https://en.wikipedia.org/wiki/Unit_testing) look at small chunks
of self-coherent code to verify the behaviour of a subroutine or module.
This is the test you write to catch corner cases or to explore code branches.
In this repository, all files with the `.t` extension are unit tests which
are found by Perl's [prove](https://perldoc.perl.org/prove) command.

The individual unit tests are located in each of the directories.
Best practice is to create a directory for each module being tested and
group similar tests together in separate files with a descriptive name,
such as **t/units/** for testing the **Units.pm** module.

Formal unit tests are located in the the `macros` and `contexts` directories that are designed to test the pg macros and contexts respectively.
Formal unit tests are located in the the `macros` and `contexts` directories
that are designed to test the pg macros and contexts respectively.

## Running the tests

```bash
cd $PG_ROOT
prove -r .
prove -lr t/
```

will run all of the tests in `.t` files within subdirectories of `t`.
Expand All @@ -23,6 +54,7 @@ prove -v pgaux.t
```

which will be verbose (`-v`).
Or you could use `prove -lv t/macros/pgaux.t` from the root directory.

## Writing a Unit Test

Expand Down Expand Up @@ -70,3 +102,34 @@ is(check_score($f->eval(x=>2),"4"),1,"math objects: eval x^2 at x=2");
```

The `check_score` subroutine evaluates and compares a MathObject with a string representation of the answer. If the score is 1, then the two are equal.


# Integration tests

[Integration testing](https://en.wikipedia.org/wiki/Integration_testing)
tests components working together as a group. The files with the `.pg`
extension are used to demonstrate the output of the rendering engine.

**TODO:** add an explanation of how to run these integration tests
and their requirements.


# Test Dependencies

The tests for **Units.pm** have brought in a new module dependency,
[Test2](https://metacpan.org/pod/Test2::V0) which is the state of the art in
testing Perl modules. It can compare data structures, examine warnings and
catch fatal errors thrown under expected conditions. It provides many tools
for testing and randomly executes its subtests to avoid the programmer
depending on stateful data.

To make these easier to install with
[cpanm](https://metacpan.org/dist/App-cpanminus/view/bin/cpanm), there is a
[cpanfile](https://metacpan.org/dist/Module-CPANfile/view/lib/cpanfile.pod)
in the root directory. Use

cpanm --installdeps .

which will install the runtime and test dependencies.
To use the cpanfile for a minimal install skipping the test requirements,
use the `--notest` option with cpanm.
6 changes: 6 additions & 0 deletions t/contexts/trig_degrees.t
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@ require("$main::pg_dir/t/build_PG_envir.pl");

## END OF TOP_MATERIAL

# remove warnings about redefining trig functions
delete $main::{sin};
delete $main::{cos};
delete $main::{atan2};


loadMacros("contextTrigDegrees.pl");

my $ctx = Context("TrigDegrees");
Expand Down
108 changes: 108 additions & 0 deletions t/lib/Test/PG.pm
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package Test::PG;

BEGIN {
die "PG_ROOT not found in environment.\n" unless $ENV{PG_ROOT};
$main::pg_dir = $ENV{PG_ROOT};
}

use warnings;
use strict;

use lib "$main::pg_dir/lib"; # only needed if not using prove with -l


=head1 Test::PG

This module provides the environment and some generic functions for
writing tests for PG macros. Mostly copied from F<t/build_PG_envir.pl>,
it also redefines Test2's "exists" function from C<E()> to C<EXISTS()>
to avoid the conflict with WebWork's exponential function.
Its final action is to load C<PGbasicmacros.pl>.

The reason for the module is that There Is More Than One Way To Do It
and people develop different styles. This is my coding style.
Also we learn the underlying structures better by re-inventing the wheel.
We just try to make a better wheel, but success is not guaranteed.

This module strives for elegance in reducing boiler plate in test files,
a minimum of duplicated code and adheres to the principle of least surprise
by locating modules below the C<t/lib> directory.
It does not make a decent cup of tea.

=head2 Usage

To test a macro that needs to be loaded, include this preamble
at the top of your test file and customize.

use Test2::V0;

use MyPGLib; # does your macro need a module?

use lib 't/lib';
use Test::PG; # setup a minimal WW environment

loadMacros("parserMyPGMacro.pl");

Context("Numeric");

And run your test from the $PG_ROOT directory with

prove -l t/my_macro/my_test.t


=head2 TODO

=head3 Quiet warnings in F<t/contexts/trig_degrees.t>

The functions sin, cos and atan2 are redefined and generate warnings.
C<delete> them from the symbol table before loading the macro.

F<macros/contextTrigDegrees.pl> declares C<$deg> twice, it being
a required file, the package scope isn't heeded by the second C<my $deg>.
I wonder if this happens every time this macro is loaded.

=cut


package main;

$main::{EXISTS} = delete $main::{E}; # redefine Test2's E() function as EXISTS()

my $macros_dir = "$main::pg_dir/macros";

# use WeBWorK::Localize;
use PGcore;
use Parser;

# build up enough of a PG environment to get things running
our %envir = (
htmlDirectory => '/opt/webwork/courses/daemon_course/html',
htmlURL => 'http://localhost/webwork2/daemon_course/html',
tempURL => 'http://localhost/webwork2/daemon_course/tmp',
pgDirectories => { macrosPath => ["$macros_dir"] },
macrosPath => ["$macros_dir"],
displayMode => 'HTML_MathJax',
language => 'en-us',
language_subroutine => sub { return @_; }, # return the string passed in instead going to maketext
);

sub be_strict {
require 'ww_strict.pm';
strict::import();
}

sub PG_restricted_eval {
WeBWorK::PG::Translator::PG_restricted_eval(@_);
}

sub check_score {
my ($correct_answer, $ans) = @_;
return $correct_answer->cmp->evaluate($ans)->{score};
}

require "$macros_dir/PG.pl";
DOCUMENT();

loadMacros('PGbasicmacros.pl');

1;
24 changes: 24 additions & 0 deletions t/units/basic_module.t
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
use Test2::V0;

use Units;

# get unit hashes
my %joule = evaluate_units('J');
my %newton_metre = evaluate_units('N*m');
my %energy_base_units = evaluate_units('kg*m^2/s^2');

# basic definitions of energy equivalence
is \%joule, \%newton_metre,
'A joule is a newton-metre';
is \%joule, \%energy_base_units,
'A joule is a kg metre squared per second squared';


# test the error handling
my $fake = 'bleurg';
ok my %error = evaluate_units($fake);
like $error{ERROR}, qr/UNIT ERROR Unrecognizable unit: \|$fake\|/,
"No unit '$fake' defined in Units file";


done_testing;
Loading