Stubbing/mocking a service in a Dancer2 application - unit-testing

Usually, I have a setup similar to this:
#!/usr/bin/env perl
package Demo;
use Dancer2;
use Moose;
sub get($self, $params) {
my $whatever = ...; # connect with db and do stuff
return $whatever;
}
my $service = Demo->new();
sub make_web_friendly($param) { # no $self, here!
return "Hello $param!";
}
get '/' => sub {
my $response = $service->get(query_parameters);
return make_web_friendly($response);
};
start;
This way, I can separate concerns pretty well and my services are testable without going over a bogus web request via Plack::Test;
However, whenever I test the request, I always also test the service, with goes against this separation.
I would want to provide the Plack Test with a stubbed service that would mock a service answer. So (I assume) either I can make the get action somehow $self-aware, or would have to pass the mocked service to Plack.
# this is put together to showcase the principle, it does not work
package Stub {
use Moose;
use Test::More;
use Data::Dumper;
sub get($self, $params) {
diag "I received:" . Dumper($params);
return "Bianca!";
}
}
my $app = Demo->to_app;
my $test = Plack::Test->create($app);
my $stub = Stub->new();
$test->service($stub);
my $request = HTTP::Request->new( GET => '/' );
my $response = $test->request($request);
is $response, 'Hello, Bianca', 'Bianca was here';
How can I achieve (something like) this?

Related

How to mock file system with Laravel and vfsStream? [Laravel 5.1]

I have request like this:
$path = storage_path('testing/unnamed.png');
$original_name = 'unnamed';
$mime_type = 'image/png';
$size = 2192;
$error = null;
$test = true;
$file = new UploadedFile($path, $original_name, $mime_type, $size, $error, $test);
$response = $this->call('POST', 'games', [
'name' => 'TEST321',
'category' => 'test',], [], ['picture' => $file], []);
And insted of storing image how can I mock file system?
Also this don't pass laravel mime validation mimes:jpeg,bmp,png... Anyone know how to fix it?
laravel allows you to mock any facade by calling the 'shouldReceive' mockery method on it:
File::shouldReceive('move')
->with('arguments');
see the docs for more information
I wrote and use a Laravel 5.4 package, https://packagist.org/packages/stechstudio/laravel-vfs-adapter to let me easily switch to a Virtual File System adapter.

Mock Middleware for route testing in Laravel

I am trying to write some unit tests to ensure my routes are not accidentally rewritten. I found already an answer to check whether a correct controller is assigned to particular route here.
However I would like to check as well that correct middlewares are assigned to route. I tried similar approach with
$tmp = new CorsService;
$corsMiddleware = Mockery::mock('Barryvdh\Cors\HandleCors[handle]', array($tmp))
->shouldReceive('handle')->once()
->andReturnUsing(function($request, Closure $next) {
return $next($request);
});
\App::instance('Barryvdh\Cors\HandleCors', $corsMiddleware);
For some reason the test is not picking this up. I am assuming that is because middleware instances are not stored using App::instance.
What am I doing wrong?
So I have found out there are 2 issues with above code
You can not chain ->shouldReceive directly with return value of Mockery::mock
there is missing \ from Closure
Working example:
$tmp = new CorsService;
$corsMiddleware = Mockery::mock('Barryvdh\Cors\HandleCors[handle]', array($tmp));
$corsMiddleware->shouldReceive('handle')->once()
->andReturnUsing(function($request, \Closure $next) {
return $next($request);
});
\App::instance('Barryvdh\Cors\HandleCors', $corsMiddleware);
Don't forget to to use ->getMock() at the end, if you are going to chain things like ->shouldReceive directly to your Mock object:
$corsMiddleware = Mockery::mock('Barryvdh\Cors\HandleCors[handle]', array($tmp))
->shouldReceive('handle')->once()
->andReturnUsing(function($request, Closure $next) {
return $next($request);
})
->getMock();
Try to get routes and check their middlewares
// Get Routes
foreach (Route::getRoutes() as $route) {
$middleware = $route->gatherMiddleware();
$name = $route->getName();
\Log::debug($name.'--');
\Log::debug($middleware);
}

Test JSON-returning controller method without MissingViewError

I am testing a Controller method that has only a JSON view. My method runs as expected, but the test method only returns "MissingViewException". Is there a solution to avoiding this exception in the unit test (besides inserting an empty file at View/People/map_leads.ctp)?
PeopleController.php
public function mapLeads($territory_id = null) {
$leads = $this->Person->getPeople([
'territory_id' => $territory_id
]);
$this->set('leads', $leads);
}
AppController.php
public $components = ['RequestHandler'];
routes.php
Router::parseExtensions('json');
PeopleControllerTest.php
public function testMapLeads() {
$id = 40;
$result = $this->testAction('/people/mapLeads/' . $id, array('return' => 'vars'));
}
View/People/json/map_leads.ctp exists and is properly utilized by CakePHP; it is only the test that wants to see View/People/map_leads.ctp.
I checked at CakePHP: calling testAction to a json-returning method causes missing view exception reminding about adding RequestHandler to $components. This does not resolve the exception.
You aren't issuing a JSON request/accessing a JSON endpoint, as neither your request URL does contain the .json extension, nor does your request send an appropriate Accept header (I don't remember whether the latter is possible with the 2.x controller test case class at all).
Use the .json extension and you should be good.
$this->testAction('/people/mapLeads/' . $id . '.json', array('return' => 'vars'));
Write this code inside your action.
$this->autoLayout = false;
$this->autoRender = false;
$this->response->type('application/javascript');

Symfony2 : Handling error on a single controller

I made a controller to provide some webservices in JSON and i would like to provide some errors informations when Symfony throw an exception ( Error 500 ) , how can i write such a thing ?
The main purpose of the webservice is to update informations in Symfony DB provided by the caller in POST values.
in my controller i return response in JSON and i would like to handle Symfony exception ( like when the values provided or not fitting the schema designed ) to return details informations about errors .
i thought about making a test of every values but it would be a long time to write and not e easy code to read or using a try / catch system , but i think Symfony already provide such a function .
What do you think ?
Thx :)
I think you should use an EventListener to catch errors and return the proper response.
You can place it inside your SomethingBundle/EventListener folder and also you need to define a service in order to be loaded by Symfony.
More info: Event Listener
I hope I helped you, if you think I might be wrong, let me know. Good luck!
EDIT
If you only want to catch the errors inside a specific controller (for example) a controller called Webservice inside your SomethingBundle, you must check it before doing anything:
public function onKernelException(GetResponseForExceptionEvent $event)
{
$request = $event->getRequest();
if($this->getBundle($request) == "Something" && $this->getController($request) == "Webservice")
{
// Do your magic
//...
}
}
private function getBundle(Request $request)
{
$pattern = "#([a-zA-Z]*)Bundle#";
$matches = array();
preg_match($pattern, $request->get('_controller'), $matches);
return (count($matches)) ? $matches[0] : null;
}
private function getController(Request $request)
{
$pattern = "#Controller\\\([a-zA-Z]*)Controller#";
$matches = array();
preg_match($pattern, $request->get('_controller'), $matches);
return (count($matches)) ? $matches[1] : null;
}
DANGER This code is not tested, is only an approach for you to build your own code. But, if I have something wrong on it, tell me. I'd like to keep my examples clean.
Use JsonResponse Symfony class in sandbox:
use Symfony\Component\HttpFoundation\JsonResponse;
$data = array(); // array of returned response, which encode to JSON
$data['error_message'] = 'Bad request or your other error...');
$response = new JsonResponse($data, 500); // 500 - response status
return $response;

Building a web service with Perl

I need to build a server-side application (tiny web service) for testing proposes. What are some CPAN modules and Perl libraries for implementing such task?
Testing a tiny Web service with Plack::Test:
use Plack::Test;
use Test::More;
test_psgi(
app => sub {
my ($env) = #_;
return [200, ['Content-Type' => 'text/plain'], ["Hello World"]],
},
client => sub {
my ($cb) = #_;
my $req = HTTP::Request->new(GET => "http://localhost/hello");
my $res = $cb->($req);
like $res->content, qr/Hello World/;
},
);
done_testing;
There are a lot of possibilities
CGI - if you like to do everything like in the olden days
CGI::Application - a little more advanced
or you could use frameworks like
Catalyst
Dancer
Mojolicious
It depends on your skills and aims what solution you should choose.
A web service simply returns a HTTP status code and some data, perhaps serialized in JSON or XML. You can use the CGI module to do this, e.g.:
#!/usr/bin/perl -w
use strict;
use warnings;
use CGI;
use CGI::Pretty qw/:standard/;
use URI::Escape;
my $query = CGI->new;
my $jsonQueryValue = uri_unescape $query->param('helloWorld');
# let's say that 'helloWorld' is a uri_escape()-ed POST variable
# that contains the JSON object { 'hello' : 'world' }
print header(-type => "application/json", -status => "200 OK");
print "$jsonQueryValue";
You can, of course, print an HTTP response with other status codes and data. A web service might need to return a 404 error, for example, depending on what's being asked for. That sort of thing.
I like to use mojolicious. It's lightweight at first and can do the heavy lifting later too. Mojolicious::Lite in particular is good for quick and dirty.
use Mojolicious::Lite;
# Route with placeholder
get '/:foo' => sub {
my $self = shift;
my $foo = $self->param('foo');
$self->render(text => "Hello from $foo.");
};
# Start the Mojolicious command system
app->start;