1. Testing with PSGI

    Doug Bell

    Plain Black Corp | WebGUI

  2. What is PSGI?

  3. Basic PSGI

    # from PSGI.pod
    my $app = sub {
          my $env = shift;
          return [
              '200',
              [ 'Content-Type' => 'text/plain' ],
              [ "Hello World" ], # or IO::Handle-like object
          ];
      };
    
  4. Testing with PSGI

  5. Run a PSGI app

    use HTTP::Message::PSGI;
    use HTTP::Request;
    use HTTP::Response;
    use MyApp; # is a Plack::Component
    
    my $app = MyApp->to_app;
    
    my $request = HTTP::Request->new;
    
    my $output = $app->( $request->to_psgi );
    
    my $response = HTTP::Response->from_psgi( $output );
    
  6. Using T::W::M::PSGI

    use Test::More;
    use Test::WWW::Mechanize::PSGI;
    use MyApp;
    my $mech = Test::WWW::Mechanize::PSGI->new( 
                    app => MyApp->to_app, );
    $mech->get_ok( '/' );
    done_testing;
    
  7. A Guestbook

  8. The App Class

    package MyApp;
    use Moose;
    use Template::Simple;
    use Plack::Request;
    use Plack::Response;
    extends 'Plack::Component';
    
    has posts => (
        is      => 'rw',
        lazy    => 1,
        default => sub { [] },
    );
    
  9. The Template

    has tmpl => (
        is      => 'ro', lazy => 1,
        default => sub {
            Template::Simple->new(
                templates => {
                    view => <<'ENDTMPL',
    <form method="POST"><label>Name:<input name="name"/></label>
    <label>Comment:<textarea name="text"></textarea></label>
    </form>
    [% START posts %]
    <p>[% name %] -- [% text %]</p>
    [% END posts %]
    ENDTMPL
                },
            );
        }
    );
    
  10. The View Method

    sub call {
        my ( $self, $env ) = @_;
    
        my $req = Plack::Request->new( $env );
        if ( $req->method eq 'POST' ) {
            $self->add_post( $req->parameters );
        }
    
        my $res = Plack::Response->new(200);
        $res->content_type('text/html');
        $res->body( $self->posts_html );
        return $res->finalize;
    }
    
  11. The Posts

    Add a Post

    sub add_post {
        my ( $self, $row ) = @_;
        push @{$self->posts}, $row;
    }
    

    Show the Posts

    sub posts_html {
        my ( $self ) = @_;
        my $output = $self->tmpl->render( 'view', $posts );
        return ${ $output };
    }
    
  12. Test the Whole Thing

    use Test::More;
    use Test::WWW::Mechanize::PSGI;
    use MyApp;
    my $mech = Test::WWW::Mechanize::PSGI->new( 
        app => MyApp->new->to_app,
    );
    
  13. Test the Form

    $mech->get_ok( '/', 'get the form' );
    $mech->submit_form_ok(
        {
            fields  => {
                name    => 'Scrappy Doo',
                text    => 'Puppy power!',
            },
        }
        "Add a guestbook entry",
    );
    
  14. Test the New Post

    $mech->content_contains( "Scrappy Doo" );
    $mech->content_contains( "Puppy power!" );
    
  15. More Tests

  16. Why?

  17. Coverage

  18. But...

  19. Questions

    Slides are licensed under a CC-BY-SA 3.0 license.

    Code is licensed under the Artistic License or GNU GPL v1.0 or later, at your discretion (the same terms as Perl 5 itself).