develooper Front page | perl.qa | Postings from September 2016

CPANifying our test framework - or parts of it

Thread Next
From:
Sam Kington
Date:
September 10, 2016 01:34
Subject:
CPANifying our test framework - or parts of it
Message ID:
92D73771-EF93-4C48-A2F8-4259E24B7E84@illuminated.co.uk
Hi,

At $WORK we have an extensive test suite that we’ve built up over the years, with loads of convenience methods for calling e.g. Dancer endpoints and checking returned data structures against what we expect. One of our dev team recently left for pastures new, and would like to carry on using these tools. How should I best extract this functionality into a proper CPAN distribution (ideally using Test2)?

At its most elaborate, our current test code lets you say e.g.

# Assume $self->state('location_id') has been set previously
$self->test(
    title => 'Create a properly megalithic structure',
    call  => [
        POST => '/location/:location_id/build',
        {
            author     => 'Wally Wallington',
            structures => [
                {
                    type     => 'dolmen',
                    material => 'concrete',
                }
            ]
        }
    ],
    expect => {
        http_code => HTTP_CREATED,
        sql_count => 12,
        data      => {
            location_id => $self->state('location_id'),
            build_id    => qr{^ (?<build_id> BUILD \d+ ) $}x,
            built       => $self->true,
            author     => $self->meh,    # It's OK if they call him Idiot.
            structures => [
                {
                    _hashref_contains => {
                        structure_id => qr{^ (?<structure_id> STRUCT \d+ ) $}x,
                        type         => 'dolmen',
                        material     => 'concrete',

                        # There's probably stuff about where the dolmen
                        # was erected but we ignore that for the purpose
                        # of this test.
                    }
                }
            ]
        }
    }
);

# $self->state('build_id') got set by the named capture in the regex above.
$self->test(
    title => 'Turn it to gold because lol',
    call  => [
        PATCH => '/location/:location_id/build/:build_id/structure/:structure_id',
        { material => 'gold' }
    ],
    expect => {
        # The same as saying data => { _hashref_contains => { material => 'gold' } }
        data_contains => {
            material => 'gold'
        }
    }
);

And if anything doesn’t quite match, it tries to show you what did and didn’t match.

The stuff in call gets passed to e.g. Dancer::Test::dancer_response or treated as a method call, depending on the invocation. As we share a common process with the code being called and tested, we can also monitor the database calls being made via DBIx::Class, and there’s some fiendish code for tracking, diagnosing and correcting test errors regarding the number of distinct database queries being made.

These are all nice-to-haves rather than something that’s inherent to the design of this testing code. What’s really useful, and what my ex-colleague is hankering after, is a couple of things:

(A) To say, flexibly, “I want a data structure that looks like this”, and to be able to say (1) this field must look exactly like this, (2) this field should look like this, and remember it, (3) this field should exist, but I don’t care what its value is, and (4) there might be additional fields but I don’t care about them for the purpose of this test.

(B) To maintain a collection of placeholders that can be updated by tests and used by subsequent tests.

I haven’t looked recently at the Test:: infrastructure, so for all I know we may have replicated functionality that we’d missed a few years ago when we started coding.

But if this functionality is new and useful, how should I implement it?

Sam
-- 
Website: http://www.illuminated.co.uk/


Thread Next


nntp.perl.org: Perl Programming lists via nntp and http.
Comments to Ask Bjørn Hansen at ask@perl.org | Group listing | About