PHPUnit + Symfony: Crawler Follow Redirects Causes SegFault - php

I have a simple PHPUnit/Symfony WebTestCase set up to test our site's login form.
$form = $crawler->filter("#register")->form();
// set form values
$crawler = $this->client->submit($form);
The form will submit to /register, and then redirect to /registered on success (and 200/OK back to /register on failure).
If I use either $this->client->followRedirects(); before block above, or $this->client->followRedirect(); after the submit, I get a segfault. There's really no indication of where the segfault is taking place.
Something else of note: if I run JUST the tests in this tests parent class (2 tests) i.e. using --filter [THE CLASS] it runs fine. If I try to run this test, along with the full suite (~15 tests), I get the segfault.
I've tried giving phpunit more memory using the -d flag, but that doesn't really help.

The problem can be in controller work in conjunction with other component.
I suggest you to use the Process Isolation in PHPUnit so you can run the critical test in a separate PHP process. As Example, you can use the following annotations for:
Indicates that all tests in a test class should be run in a separate PHP process:
/**
* #runTestsInSeparateProcesses
*/
class MyTest extends PHPUnit_Framework_TestCase
{
// ...
}
Indicates that a test should be run in a separate PHP process:
class MyTest extends PHPUnit_Framework_TestCase
{
/**
* #runInSeparateProcess
*/
public function testInSeparateProcess()
{
// ...
}
}
Hope this help

Related

Laravel 8 not running newly created tests, and not picking up deleted tests

I'm just getting started with the Laravel 8 testing suite and have opted to create a feature test for my account creation process. I've ran php artisan make:test AccountCreation and have written the first test case as a function, however, when I run php artisan test it's not picking up my feature tests, why?
Equally, if I try to delete the default example test, I get an error telling me that the test can't be found? What am I missing?
tests/Feature/AccountCreation.php
<?php
namespace Tests\Feature;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Illuminate\Foundation\Testing\WithFaker;
use Tests\TestCase;
class AccountCreation extends TestCase
{
/**
* A basic feature test example.
*
* #return void
*/
public function test_creates_user_account_successfully()
{
$response = $this->post('/api/account/create');
$response->assertStatus(201);
}
}
Is there a special command I need to run for Laravel to pick up these tests?
Because you should append 'Test' to your test class, because PHPUnit will check all classes end with Test, so change:
class AccountCreation extends TestCase { ...
to:
class AccountCreationTest extends TestCase { ...
Don't forget to change your class file name.
/** #test */
Put this before every test. It worked for me.

Laravel PHPUnit GET and POST always returning 404

Writing up Unit Tests in a Laravel project and whilst for the most part it has been very straight forward with PHPUnit, the TestCase methods of get and post do not work with my application; always returning a 404.
Currently the test in question passes as I'm just trying to run the following:
class HttpTests extends TestCase
{
/**
* A basic test example.
*
* #return void
*/
public function testExample()
{
print_r($this->get('/')->getContent());
}
}
Which outputs the markup of the 404 page of the application.
I know that the correct url is being queried, as adding...
{{ Request::url() }}
To 404.blade.php echos the correct URL that I have defined in my .env file as
APP_URL=http://127.0.0.1:8000
Not sure how else to fix it, when using more complex solutions like Dusk I never had issues using the visit method but it appears to only occur with the built in HTTP request functions for Laravel's TestCase class.

Symfony 2.6 overrides PHPUnit_Framework_Error

I have a unit tested application which we have updated from symfony 2.3 to 2.6. We followed all upgrading docs and had to change only some minor stuff.
Everything is working perfectly, except for the PHPUnit tests.
We have 2 seperate runs, one for only testing the entity classes, which is fired on a pre-commit hook. and a second one which runs the full suite, with database setups and the whole nine yards.
Now since the upgrade to 2.6, the PHPUnit_Framework_Error thrown in the unit tests have been replaced by Symfony's Symfony\Component\Debug\Exception\ContextErrorException, this failing all tests like this:
/**
* #dataProvider objectTestDataProvider
* #expectedException \PHPUnit_Framework_Error
*/
public function testCanNotSetClientToArbitraryValue($value)
Now I do not want to change this into the new Exception since running the entity-only test suite does not depend on symfony components, thus symfony is not loaded, thus the errors are the regular PHPUnit_Framework_Error so changing it makes these tests fail.
In other words, when I run one test class it works, once a symfony dependent test is run, it fails:
# runs perfectly
phpunit -c app/phpunit.xml --debug src/My/Bundle/Tests/Entity
# fails when reaching the tests that ran perfectly in previous command
phpunit -c app/phpunit.xml --debug
This new ErrorHandler seems undocumented, I couldnt find much about it in google except for the pull request and this small article
I've tried:
setting the SYMFONY_DEBUG=0 environment variable, but this doesnt seem to make any difference.
adding the debug.error_handler.throw_at: 0 parameter to my test_config.yml
edit:
On request by #cerad I've tried to isolate the tests to try and reproduce the code with as little as possible, Ive managed to reproduce with 4 tests:
class MyControllerTest extends WebTestCase
{
public function testRoutesLoaded_1()
{
$client = self::createClient();
/** #var Router $router */
$router = $client->getKernel()->getContainer()->get('router');
$this->assertEquals('/menu', $router->generate('front_menu'));
}
/**
* #expectedException \PHPUnit_Framework_Error
*/
public function testCreateOrder_1()
{
new Order(); // required parameter missing
}
public function testRoutesLoaded_2()
{
$client = $this->createNewFrontClient();
/** #var Router $router */
$router = $client->getKernel()->getContainer()->get('router');
$this->assertEquals('/menu', $router->generate('front_menu'));
}
/**
* #expectedException \PHPUnit_Framework_Error
*/
public function testCreateOrder_2()
{
new Order(); // required parameter missing
}
}
As you can see, I just run the same exact test 2 times, but still the last one results in an error:
MyControllerTest::testCreateOrder_2
Failed asserting that exception of type "Symfony\Component\Debug\Exception\ContextErrorException" matches expected exception "\PHPUnit_Framework_Error"
Since I did not get any replies here, I posted an issue on Symfony's github and they confirmed this was incorrect behavior.
The issue was resolved and is merged in 2.6-dev.

PHPUnit and Selenium - run tests from another class

I am using PHPUnit and Selenium to test my web application.
At the moment I have 2 test classes - UserTest and PermissionsTest.
In UserTest I have methods which test that the program can successfully create a new user.
In PermissionsTest I turn certain permissions on and off and test the outcome.
For instance, I might turn the 'Create User' permission off and then test that the 'Create User' button is disabled. However, if I turn the 'Create User' permission back on, I want to test that it is possible to create a user.
All of the logic for being able to create a user is already in the UserTest class - so is there any way of running tests from the UserTest class from the PermissionsTest class?
At the moment I am trying the following code:
public function testUserPermission(){
$userTest = new UserTest();
if($this->hasPermission = true){
$userTest->testCanCreateUser();
}
}
However when I run this test, I get the error "There is currently no active session to execute the 'execute' command. You're probably trying to set some option in setup() with an incorrect setter name..."
Thanks!
It sounds to me like you're missing separation of your test implementation with its logic - I'm not talking about PHP issue but general test model.It will allow you to reuse your test components in various test cases.
You can take a look on some
material about Page Objects in PHP here or general selenium wiki.
The solution was as follows:
//instantiate and set up other test class
$userTest = new UserTest();
$userTest->setUpSessionStrategy($this::$browsers[0]);
$userTest->prepareSession();
//carry out a test from this class
$userTest->testCanCreateUser();
This works nicely. I can't see why using functionality from another test class is a bad idea in this case, because if I didn't do that I'd have to just rewrite that functionality into my new class, which seems less 'pure'...
For Selenium 1 (RC),
I made the following modifications instead (as well as applying the Page Object design pattern):
Specific Test class
//instantiate and set up other test class
$userTest = new UserTest($this->getSessionId());
//carry out a test from this class
$userTest->createUser();
//asserts as normal
$userTest->assertTextPresent();
...
Base Page Object class
class PageObject extends PHPUnit_Extensions_SeleniumTestCase {
public function __construct($session_id) {
parent::__construct();
$this->setSessionId($session_id);
$this->setBrowserUrl(BASE_URL);
}
}
Specific Page Object class
class UserTest extends PageObject {
public function createUser() {
// Page action
}
}

Mockery shouldReceive()->once() doesn't seem to work

I'm trying to get Mockery to assert that a given method is called at least once.
My test class is:
use \Mockery as m;
class MyTest extends \PHPUnit_Framework_TestCase
{
public function testSetUriIsCalled()
{
$uri = 'http://localhost';
$httpClient = m::mock('Zend\Http\Client');
$httpClient->shouldReceive('setUri')->with($uri)->atLeast()->once();
}
}
As you can see, there's one test that (hopefully) creates an expectation that setUri will be called. Since there isn't any other code involved, I can't imagine that it could be called and yet my test passes. Can anyone explain why?
You need to call Mockery:close() to run verifications for your expectations. It also handles the cleanup of the mockery container for the next testcase.
public function tearDown()
{
parent::tearDown();
m::close();
}
To avoid having to call the close method in every test class, you can just add the TestListener to your phpunit config like so:
<listeners>
<listener class="\Mockery\Adapter\Phpunit\TestListener"></listener>
</listeners>
This approach is explained in the docs.
One thing to note from the linked docs is:
Make sure Composer’s or Mockery’s autoloader is present in the bootstrap file or you will need to also define a “file” attribute pointing to the file of the above TestListener class.
Just a sidenote: If you use Laravel: the make:test --unit generates a test class that extends the original PhpUnit Testcase class and not the included Tests\Testcase, which loads the laravel app and runs the Mockery::close(). It is also the reason why in some cases your tests fail if you use Laravel specific code (like Cache, DB or Storage) in the units you're testing.
so if you need to test units with Laravel specific code, just swap out the 'extends Testcase' and there is no need to call Mockery::close() manually

Categories