I have one test case with two tests in it like so:
class LoginTest extends TestCase {
use DatabaseMigrations;
public function testSeeLoginForm() {
$this->visit('/backend');
}
public function testCanLogin() {
$this->visit('/backend');
}
}
The 2 tests are identical but the first one passes and the second one fails with a 404 (A request to [http://localhost/backend] failed. Received status code [404].)
What am I doing wrong?
After a long journey searching for the problem I finally fixed it.
Apparently, when testing routes, using require_once instead of require breaks the testing.
Related
I am trying to use overload option of Mockery library on Laravel 5.
My current environment:
Laravel 5
Mockery 1.0
PHPUnit 7.5
I wrote this test case:
namespace Tests\Unit;
use Mockery;
use Tests\TestCase;
/**
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
*/
class RenewSignatureTest extends TestCase
{
public function testHandle()
{
$mock = Mockery::mock('overload:App\FooClass');
$mock->shouldReceive('callBar')
->times(2);
}
}
According to documentation, this test should fail, but does not matter what I do, the test never fails! It always result in:
Time: 304 ms, Memory: 19.53 MB
OK (1 test, 1 assertion)
If I remove the overload: option, the test fails. So I assume that I'm not using the library's methods as expected.
The new test:
namespace Tests\Unit;
use Mockery;
use Tests\TestCase;
/**
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
*/
class RenewSignatureTest extends TestCase
{
public function testHandle()
{
$mock = Mockery::mock('App\FooClass');
$mock->shouldReceive('callBar')
->times(2);
}
}
The result:
Mockery\Exception\InvalidCountException: Method callBar(<Any Arguments>) from Mockery_0__App_FooClass should be called exactly 2 times but called 0 times.
Am I doing anything wrong? Does anyone know how to use this option properly?
Reading the page, I think this is the error you are looking for:
When Mockery overloads a class, because of how PHP works with files,
that overloaded class file must not be included otherwise Mockery will
throw a “class already exists” exception. This is where autoloading
kicks in and makes our job a lot easier.
The error that you're looking for will be caused if you remove these 2 lines from your test, which are added to the code in the second code sample, and in the third sample on the manual page:
* #runTestsInSeparateProcesses
* #preserveGlobalState disabled
This means your code wont take advantage of the psr4 autoloader or any autoloader that is in place, and will create a new autoloader for you, at the expense of speed, since it wont be using your dumped classmap and has to build it up from scratch.
If you take the two lines above out, you will get the expected error, as it will try to overload your class with a class of the same name. That class will already be autoloaded, so you get a fatal error.
So if you want to block calls to callBar, and return void, that is what your code will be doing, which is correct.
Removing overload will mean your mock is no longer effective, as you will have to pass it through a constructor to get it to work.
Update:
With your update, I can conclude that your code must be running the mocked callBar method twice (not the actual callBar method), with your mock of fooBar class using overload. When the mocked method gets called, nothing inside the real callBar method actually happens, it just registers that it was called. If you're expecting it once for example, write shouldReceive(1) and then fix the code that your test runs.
When you remove the overload, the global injection doesnt take place, so your mock never gets injected. However, your mock callBar method on the mock class is still expecting to be ran twice, so you get the error. You will need to remove the 2 mock code lines completely from your test.
Keep the # statements in, as it will help prevent the psr4 error outlined above.
This is not the way to test, you should never use overload: option... Laravel helps you with a lot of things, don't create the wheel again or try to...
Why would you need to use #runTestsInSeparateProcesses and #preserveGlobalState disabled ?
Let's say your test is like this:
namespace Tests\Unit;
use App\FooClass;
use App\Service\ServiceForTesting;
use Mockery;
use Tests\TestCase;
class RenewSignatureTest extends TestCase
{
public function testHandle()
{
$mock = Mockery::mock(FooClass::class);
$mock->shouldReceive('callBar')
->times(2);
$myClass = app(ServiceForTesting::class);
$myClass->run($mock);
$myClass->run($mock);
}
}
You should have a code like this:
namespace App;
class FooClass
{
public function callBar()
{
return 'Works !!!';
}
}
Now, let's say you have a standalone class (no controller or similar, you are in a unit test), you should have something like this:
namespace App\Service;
use App\FooClass;
class ServiceForTesting
{
public function run(FooClass $class)
{
return $class->callBar();
}
}
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
I am going through a Laracast tutorial which suggest me to have the statement use DatabaseTransactions; inside my test class definition, to allow the data changes in my test case will persists only for that case.
I have a test class,
Class MyClassTest extends TestCase
{
// This use statement is responsible for
//all the data operations to persists only with in that test case
use DatabaseTransactions;
/**
* #test
*/
public function my_test_function()
{
// My test case code. Which inserts/updates
//data and assert statement.
}
}
The use DatabaseTransactions works in a way that the data changes in the method persists only with in that. How that works exactly?
As went further, DatabaseTransactions is trait, which contains the method beginDatabaseTransaction with #before annotation.
Having an use DatabaseTransactions within the test class lets the class have that method.
Since the method beginDatabaseTransaction contains a #before annotation, it will be executed before every test case.
The below is the method definition which begins a transaction and rolls back existing transaction before the test case finishes(it is still unclear why #before should be called before the test case finishes).
#before
public function beginDatabaseTransaction()
{
$this->app->make('db')->beginTransaction();
$this->beforeApplicationDestroyed(function () {
$this->app->make('db')->rollBack();
});
}
I'm trying to use the extension php_pthreads with Symfony2.
I set up a simple controller:
<?php
namespace Test\TestBundle\Controller;
use Symfony\Bundle\FrameworkBundle\Controller\Controller;
class SimpleThread extends \Thread {
public function run() {
sleep(100);
}
}
class DefaultController extends Controller
{
public function indexAction()
{
$simpleThread = new SimpleThread();
$simpleThread->start();
return $this->render('TestTestBundle:Default:index.html.twig', array('name' => "World"));
}
}
And it just gives me a blank page (ERR_CONNECTION_RESET). I have nothing to try to fix it since there is no error, I don't know how to debug this.
When I try to run this simple test code (https://stackoverflow.com/a/15501449/3070307) outside of Symfony, it works fine.
Any help is much appreciated.
EDIT:
Ok two things:
sleep(100);
Sleeps for 100 seconds... I miss-typed usleep.
Second, the Symfony cache is messing with thread execution apprently, disabling it fixed it (http://symfony.com/doc/current/cookbook/debugging.html).
The only remaining problem is the render function does nothing, I'm not even sure it's called.
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