How to get get page source in codeception yii 2 - unit-testing

I need save the source code of failed test to fix it. How to get the source html while using codeception test in yii 2?
I cannot get $I->grabPageSource() and $I->_getResponseContent() to work though there are these exact functions.
public function checkCall(FunctionalTester $I)
{
$I->amOnRoute('mx/ed',['model' => 'State']);
$I->seeResponseCodeIs(200);
$I->seeResponseCodeIsSuccessful();
$html = $I->grabPageSource();
}

Codeception saves page source of last request for all failed tests in tests/_output directory by itself, there is nothing for you to do.
Failed assertion throws exception so your code after $I->seeResponseCodeIsSuccessful is not executed.
If you want to implement some custom error handling in specific test, you can wrap assertions in try-catch block and grabPageSource inside catch.
public function checkCall(FunctionalTester $I)
{
$I->amOnRoute('mx/ed',['model' => 'State']);
try{
$I->seeResponseCodeIs(200);
$I->seeResponseCodeIsSuccessful();
} catch (Exception $e) {
$html = $I->grabPageSource();
//do your error handling here
throw $e; //rethrow exception to make test fail
}
}
If you want to implement custom error handling for all tests, add _failed method to Helper\Functional class in tests/_support/Helper directory.
public function _failed(\Codeception\TestInterface $test, $fail)
{
$testName = $test->getMetadata()->getName();
$pageSource = $this->getModule('Yii2')->getPageSource();
//do your error handling here
}

Related

Symfony3 and PHP 7 return type decleration for Doctrine Repository methods

I really like PHP's return type declarations, and I want to use it on Symfony 3.
All controller methods should return a Response object, no problem there. But in Doctrine repositories though, Doctrine might return an Entity object, or null.
Consider this example:
You have created a simple Post entity.
You have created a custom findByName method in PostRepository:
PostRepository.php
public function findByName($name) : Post
{
$qb = $this->createQueryBuilder('p')
->where('p.name = :name')
->setParameter('name', $name);
$post = $qb->getQuery()->getOneOrNullResult();
return (null === $post) ? new Post() : $post;
}
You call this method from a controller, like this:
DefaultController.php
/**
* #Route("/", name="homepage")
*/
public function indexAction(Request $request)
{
$em = $this->getDoctrine()->getManager();
$repository = $em->getRepository('AppBundle:Post');
try {
$post = $repository->findByName('test');
} catch (\TypeError $e) {
$post = new Post();
}
return new Response(dump($post));
}
I am aware trying to catch exception won't execute because findByName() always returns a Post object.
My question is, where should we handle the exception? According to this answer, it is better to throw an exception. Should we ensure repository method does not throw an exception at all by using this:
$post = $qb->getQuery()->getOneOrNullResult();
return (null === $post) ? new Post() : $post;
or let PHP throw a TypeError exception and let controller handle it?
Doctrine, throws exceptions for getOneOrNullResult() and getSingleResult() methods as described here.
If this scenario doesn't make sense because it's better to let your controller handle the exception and return a "not found" page because post doesn't exist like this:
return $this->createNotFoundException();
Scenario #2
Post exists in the database, and another repository method is called, getApprovedComments(), no comments are returned, we're expecting an ArrayCollection but we get an array. This will throw PHP's TypeError exception.
I think code is going to be full of try/catch blocks. Is it ok to handle this kind of exceptions at a higher level to have less try/catch blocks in code?
At a second thought this is not the best solution, because code should be flexible enough to catch every TypeError exception and take proper action on how to render the page.

Laravel 5 Cannot Mock View

I'm trying to write a really basic test for one of my controllers
/**
* THIS IS MY CONTROLLER. $this->badge is a repository
* #return \Illuminate\Http\Response
*/
public function index()
{
return view('badges.index')->with([
'badges' => $badges = $this->badge->all()
]);
}
I'm using repositories which return Eloquent collections. My basic test is as follows:
public function testItShowsAllBadges()
{
// Arrange
//DISABLE AUTH MIDDLEWARE ON THIS ROUTE
$this->withoutMiddleware();
// MOCK THE REPO
$this->badge->shouldReceive('all')->andReturn(new Illuminate\Support\Collection);
// Act
$response = $this->action('GET', 'BadgeController#index');
// Assert
$this->assertResponseOk();
$this->assertInstanceOf('Illuminate\Support\Collection', $response->original->getData()['badges']);
$this->assertViewHas('badges');
}
This test fails with a message 'trying to get property of non-object'. This is because I do Auth::user()->something in the view.
So I need to mock the view but I don't know how. Can someone advise?
Other SO answers do not seem to work and just result in Exceptions being thrown in the test about methods not existing on the Mock. I have tried for example:
View::shouldReceive('make')
->once()
->andReturn(\Mockery::self())
Adding this before I call the route results in a 500 error 'Method Mockery_1_Illuminate_View_Factory::with() does not exist on this mock object'. I tried adding in
->shouldReceive('with')
->once()
->andReturn(\Mockery::self());
However this results in an Exception stating that getData() does not exist on this Mock Object. Even removing that assertion, assertViewHas('badges') fails saying the response was not a view.
Also I haven't understood if View::shouldReceive... is part of Arrange or Assert phase of the test?My understanding it is part of the arrange and should go before the $this->action(....)

Unit testing grails controllers that use declarative exception handling

Let's say I have the following code:
class SomeController {
def fooService
def controllerMethod() {
def bar = fooService.doSomething()
// render bar to user - success case
}
def fooExceptionHandler(FooException e) {
// log, render error page, etc...
}
}
Based on grails' new declarative controller exception handling mechanism, if fooService.doSomething() throws an exception, grails will call fooExceptionHandler for me. Great.
Now when I unit test this method (test class uses the #TestFor(SomeController) annotation), this will fail saying that we expected a FooException but got nothing.
#Test(expected=FooException)
def doSomethingThrowsFooException() {
// override default service behavior, trigger a FooException
controller.fooService = [ doSomething: { throw new FooException() }]
controller.controllerMethod()
}
However, this works:
#Test
def doSomethingThrowsFooException() {
// override default service behavior, trigger a FooException
controller.fooService = [ doSomething: { throw new FooException() }]
controller.controllerMethod()
assert response.json == false
}
So the only way to test this method is by asserting that the response was what was expected but due to the declarative exception handling, this logic is now somewhere else (tested in isolation), not in the unit of code I am testing. Shouldn't my unit test only verify that the exception was propagated out of the controller method?
I would test the fooService integration with your controller in an integration test if possible, but I think that's only really testable sensibly in a functional test. You're really testing Grails - you're verifying that documented behavior occurs in your app.
If you add some code to throw an exception and then extra code to catch it and route it to the handler, you're just mocking out the stuff that Grails provides. Tests of that just test your mocking code, but have little to do with how well your code will work in production.
The unit test opportunity here is inside fooExceptionHandler. Test that given an exception, you do the right thing with it.

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;

PHPUnit 3.7.19 and Symfony2 broken tests

I'm developing some test for a Symfony2.0 project and running them with PHPUnit.
On my PC works fine but trying them in other environments the tests fails. I thought the problem was php version but after run them in differents environments I'm lost.
My environment is Ubuntu 12.04 and PHP 5.3.10 => Works fine.
2 PC with Ubuntu 12.10 and PHP 5.4.6:
Fatal error: Call to a member function get() on a non-object
This error is on a class which extends Symfony\Bundle\FrameworkBundle\Test\WebTestCase where is overwritten the setUp() and tearDown() methods.
public function setUp()
{
$this->client = static::createClient();
$this->client->followRedirects(true);
$crawler = $this->client->request('GET', '/admin/login');
$loginForm = $crawler->selectButton('save')->form(array(
'_username' => 'user',
'_password' => 'pass'
));
$this->client->submit($loginForm);
$this->container = $this->client->getContainer();
parent::setUp();
}
public function tearDown()
{
//Here is get() on a non-object, $this->container doesn't exists
$this->container->get('doctrine.odm.mongodb.document_manager')->getConnection()->close();
parent::tearDown();
}
2 PC, one with Ubuntu 12.10 and PHP 5.4.6 and other with Windows 7 and PHP 5.3.8:
PHP Fatal error: Call to a member function getSite() on a non-object
This error is on a class which extends the above class that has tearDown() method wrong but in this case this class works and the error is different although is related with $this->container:
//In this case, the user doesn't exists
$site = $this->container->get('security.context')
->getToken()->getUser()->getSite();
The problem is I don't know why is this. If this is related to PHP, PHPUnit(All of us have the same version), Symfony2.0 or SO.
Edit:
Ok, problems solved.
First:
Fatal error: Call to a member function get() on a non-object
Had a wrong line of code in the class which has setUp() and tearDown() methods. A line like that:
$link = $crawler->filter('a:contains("Test")')->eq(1)->link();
I had this line commented, sorry :). But I don't know why PHPUnit show me this error and not the error of link method.
Second:
PHP Fatal error: Call to a member function getSite() on a non-object
In the others environments, the test database had not been deployed.
This question will not help anyone but help me to try new things. Thanks!
It is an exected behavior for PHPUnit.
I managed to reproduce the error with the following code:
final class ExceptionErrorTest extends PHPUnit_Framework_TestCase
{
/**
* #var MyObject
*/
private $object;
public function setUp() {
throw new \RuntimeException();
$this->object = new MyObject();
}
public function testItShouldNeverBeCalled()
{
var_dump('never called');
}
public function tearDown()
{
$this->object->neverCalled();
}
}
class MyObject
{
public function neverCalled() {
return true;
}
}
// will ouput PHP Fatal error:
Call to a member function neverCalled() on a non-object in ExceptionErrorTest.php on line 22
To explain more clearly, PHPUnit will catch any exceptions triggered in the setUp method (in order for the printers to show at the end of the execution).
After that you can see that the tearDown() is called to finish the test, but since the initialization of the attribute was never reached, a PHP error is issued, and PHPUnit will never reach the code where it shows all the exceptions that occurred.
That is why you did not get the exception. To fix this, you need to make sure that any code that can throw exceptions in the setup is wrapped in a try() catch () statement like this:
public function setUp() {
try {
throw new \RuntimeException('My message');
} catch (\Exception $e) {
echo 'An error occured in the setup: ' $e->getMessage();
die;
}
$this->object = new MyObject();
}
Hope it helps someone in the future.