I wanna mock an api with success and failed results, while the request failing will throw RequestException but I cannot use It cause it's asking for arguments like response and stuff but other Exceptions like ConnectionException will happen without needing additional parameters. any thoughts?
$wrongOtp = 12345;
$this->instance(Some::class, Mockery::mock(Some::class, function (Mockery\MockInterface $mock) use ($wrongOtp) {
$mock->shouldReceive('getProfile')->with($this->ssn, $wrongOtp, $this->track_code)
->andThrow(RequestException::class)->once();
}));
so If I replace RequestException with ConnectionException in my code above it will run the test without problem but if I use RequestException it asks for a response as first argument and I actually don't know which type of response should I provide for it.
Thanks in advance for all the help
Related
I am working on a PHP project that requires validating a JSON request to a predefined schema, that is available in swagger. Now I have done my research and have found that the best project for this is SwaggerAssertions:
https://github.com/Maks3w/SwaggerAssertions
Within SwaggerAssertions/tests/PhpUnit/AssertsTraitTest.php, I would love to make use of the testAssertRequestBodyMatch method, where you do this:
self::assertRequestBodyMatch($request, $this->schemaManager, '/api/pets', 'post');
This assertion above does exactly what I need, but if I pass a invalid request it causes a fatal error. I want to trap this and handle the response back rather than the app quitting altogether.
How can I make use of this project, even though it looks like its all for PHPUnit? I am not too sure how one would make use of this project in normal PHP production code. Any help would be greatly appreciated.
Assertions throw exceptions if the condition is not met. If an exception is thrown, it will stop all following code from being executed until it's caught in a try catch block. Uncaught exceptions will cause a fatal error and the program will exit.
All you need to do to prevent your app from crashing, is handling the exception:
try {
self::assertRequestBodyMatch($request, $this->schemaManager, '/api/pets', 'post');
// Anything here will only be executed if the assertion passed
} catch (\Exception $e) {
// This will be executed if the assertion,
// or any other statement in the try block failed
// You should check the exception and handle it accordingly
if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
// Do something if the assertion failed
}
// If you don't recognise the exception, re-throw it
throw $e;
}
Hope this helps.
I've just started with php unit.
In my test cases UsersController should return:
public function UsersController() {
....
throw new \Cake\Network\Exception\NotFoundException();
}
phpunit code
$this->setExpectedException('Cake\Network\Exception\NotFoundException');
returns an assertion failed that looks like:
App\Test\TestCase\Controller\UsersControllerTest::testActivate
Failed asserting that exception of type "Cake\Network\Exception\NotFoundException" is thrown.
Meanwhile browser return a 404 PageNotFound and $this->assertResponseOk() returns:
App\Test\TestCase\Controller\UsersControllerTest::testActivate
exception 'Cake\Network\Exception\NotFoundException' with message 'Not Found' in /vagrant/ifmx.local/src/Controller/UsersController.php:215
Does somebody know why it's happened? And is there any way to get exception message in unit test.
You seem to have misunderstood how the integration test case works.
It doesn't just wrap a call to a controller method, like $controller->action(), it simulates a whole request, and as such, exceptions are being catched, and result in error pages being rendered, just like it happens when you are visiting a URL in your browser.
So PHPUnit will never know about the exception, and thus you cannot use the expected exception feature as you would when directly testing specific code parts where exceptions bubble up to PHPUnit. If that would happen, then it wouldn't be possible to assert responses, which one might want to do, even when an exception has been thrown.
Possible exceptions are being buffered in the IntegrationTestCase::$_exception property, which you can for example use to test if, what kind of exception has been thrown, etc, like
$this->assertInstanceOf('\Cake\Network\Exception\NotFoundException', $this->_exception);
$this->assertEquals('Not Found', $this->_exception->getMessage());
Sorry for this vague title, I didn't know how to title my question.
I'm listening on kernel.exception via the kernel.event_listener service. I use it in my API to catch all exceptions and serialize them in JSON for a clean error handling for the API customers.
I have to adapt the serialization depending on the exception types (my HTTP exceptions, Symfony HTTP exceptions, and others).
When a user is not authenticated when accessing a section restricted by access_control in security.yml, Symfony throws a non-HTTP Symfony\Component\Security\Core\Exception\InsufficientAuthenticationException. In my serializer, a non-HTTP exception is converted in a 500 error. Since an InsufficientAuthenticationException is rather a 401 Unauthorized error, I have to catch this exception separately and convert it in my app-specific exception type.
Example:
# Find appropriate serialization
if($ex instanceof HttpErr\HttpErrorInterface) {
# AppBundle\Exceptions\Http\*
# A displayable error thrown intentionally by our controllers
$status = $ex->getStatusCode();
$message = $ex->getMessage();
$other = $ex->getAdditionalDatas();
} elseif($ex instanceof InsufficientAuthenticationException) {
throw new HttpErr\EUnauthorized; # look a this line
}
# more elseifs...
That works. The Symfony authentication exception is catched, then converted in EUnauthorized, and then EUnauthorized is serialized into JSON. But you can see that I throw the exception without message or previous exception.
Because I want to do this:
elseif($ex instanceof InsufficientAuthenticationException) {
# the standard argument $previous is in 2nd position in my exceptions instead of being 3rd.
# the previous argument is important for me since it will keep context in error propagation.
throw new HttpErr\EUnauthorized($ex->getMessage(), $ex);
}
When I do this (so, just adding two arguments), the serialization stops working, my event listener is not called and the app crashes (in prod, this will turn into a friendly WSoD):
Why?
In the first "if" you extract data for serialization, in the second you are just rethrowing a new exception.
This new exception does not go the kernel.exception flow anymore. It is correctly just thrown: as you can see you have the full stack of exceptions shown.
Ideally, you should end your onKernelException with some kind of Response.
EDIT
I'll expand a bit my previous answer with references to the Symfony documentation and code.
The HttpKernel docs say
If an exception is thrown at any point inside HttpKernel::handle, another event - kernel.exception is thrown. Internally, the body of the handle function is wrapped in a try-catch block. When any exception is thrown, the kernel.exception event is dispatched so that your system can somehow respond to the exception.
So, your listener is called after an exception in the handle function, but, as you can see in source no try/catch is provided by the handleException function. This basically means that an Exception thrown in your listener should not be caught.
In your listener you could swap the current exception with a new one with $event->setException(...) or just try to build a Response yourself.
In any case, throwing a new Exception does not seem the proper way here. I sadly don't know why you code works with or without parameters without all the code involved.
I don't know if it helps here, but I had similar problem my event listener is not called and the app crashes. So i worked around that and overrided one method in Kernel.php file like that:
protected function initializeContainer() {
try {
$container = parent::initializeContainer();
} catch (\Throwable $throwable){
// MY CATCH CODE GOES HERE
}
return $container;
}
You can also hook up to other Kernel methods and override them.
Notice: I'm using Symfony 4.2.*
I am using Symfony 2.4 and am trying to create a more powerful exceptions handler that, on certain PDO / Doctrine exceptions, changes the status code of the response from 500 to 503 to display a different custom error message than our standard (in other words, it returns the error503.html.twig template rather than error500.html.twig). So far, I have created a custom Exceptions controller that extends the TwigBundle ExceptionController, I have changed the Twig exception parameter in config.yml, and I am able to catch any and all exceptions that are thrown once Symfony calls handle(...) in HttpKernel.php:185 (so it's really the second time that handle is called -- this time being on the HttpKernel rather than the AppKernel). I'll refrain from posting all that code, and instead direct the reader here to learn more about my method if they are unfamiliar. All of that code is working just fine -- I am able to modify any applications that are thrown within my application, so you can assume that I'm using the aforementioned approach properly.
The issue I am running into is that in addition to catching exceptions that are thrown within Symfony, I also want to also be able to catch exceptions that are thrown before the HttpKernel's handle method is called (an example being a PDO Access Denied exception that is thrown from improper database credentials). To give you a more specific rundown, in app_dev.php, you have:
$response = $kernel->handle($request);
which calls:
/**
* {#inheritdoc}
*
* #api
*/
public function handle(Request $request, $type = HttpKernelInterface::MASTER_REQUEST, $catch = true)
{
if (false === $this->booted) {
$this->boot();
}
return $this->getHttpKernel()->handle($request, $type, $catch);
}
Now, if an exception gets thrown in $this->boot(), it doesn't look like it gets caught anywhere, and because of that, I can't see any way of gracefully handling said exception in Symfony. It's only if the exception gets thrown within the try / catch block contained in $this->getHttpKernel()->handle($request, $type, $catch) that it will be caught and gracefully handled using Symfony code. Am I wrong about that? Does anyone know of an approach to handling exceptions that are thrown in this context that utilizes Symfony? My apologies in advance if this has already been answered elsewhere.
I ran into a similar problem, I didn't see a neat way around this but was able to get nice error pages for my specific problem simply by generating a Response object and sending that. I placed the following in some code which was called by boot()
try {
someExceptionFunction();
} catch (Exception $e) {
$response = new Response('<html><body>'.$e->getMessage().'</body></html>');
$response->send();
exit;
}
You could easily add some more logic to the catch block, catching different exceptions. It's not as clean/abstract as it could be, but since the entire framework fails to boot I don't know of any option you could use it to parse an error page.
Hope this helps
I'm currently working on an open source personal project that provides a nice backend api for game developers. I'm in the early stages of development, but I plan to write tests as I go along, which is where I've hit a snag.
Through out the system when an error occurs such as incorrect api credentials or missing credentials, I throw a custom exception which stores a bit of extra data so that I can catch it and give a JSON encoded response.
The tests work fine for those thrown in my BaseController, but I also capture a few Laravel Exceptions so I can respond with my own, or at least, output JSON like below:
app/start/global.php
App::error(function(Exception $exception, $code) {
Log::error($exception);
});
App::missing(function(Exception $exception) {
return BaseController::error(
Config::get('response.method.code'),
Config::get('response.method.http'),
'Method not found'
);
});
App::error(function(Viper\Exception $exception) {
return BaseController::error(
$exception->getCode(),
$exception->getStatusCode(),
$exception->getMessage()
);
});
I'm using the try { } catch() { } approach as I need to check an extra value that isn't in the normal Exceptions.
public function testNoMethodGET() {
$config = Config::get('response.method');
try {
$this->call('GET', '/');
} catch(\Viper\Exception $e) {
$this->assertEquals($e->getCode(), $config['code']);
$this->assertEquals($e->getStatusCode(), $config['http']);
}
$this->fail('Exception not thrown');
}
This is all good and well, but I want to check a few things on the actual response, like for example, whether or not the json is valid, whether or not the response structure matches and whether or not the response values are correct.
If I set the return value of $this->call() to a variable, I'd be unable to access that variable within the catch block, so the question is this, how can I test the return value of $this->call() once the Exception has been caught?
According to Taylor Otwell:
"this can be solved by de-coupling your
test. You really want to test the handler and that the exception is
thrown totally separately anyways [sic] to isolate your tests. For
instance:
App::error(function(ErrorType $e)
{
App::make('ErrorTypeHandler')->handle($e);
});
Now you can write test cases for ErrorTypeHandler class separately
from the rest of your application. Then check that proper exceptions
are thrown by your app with #expectedException."
see How do you test your App::error implementations?
In your case, you already have isolated your error handler in BaseController::error(), so you can test the responses directly in separate unit tests, without the use of $this->call(). Instead, just call $response = BaseController::error() with the desired parameters and then inspect the response and apply relevant assertions.