Testing your code is essential in order to develop reliable application. Besides classic unit tests for your services and/or controllers you are able to test your application as whole using isolated environment.
Locate this file in tests
directory of your application, by default it configured to work with default .env
. Test built in a way so your application will be constructed and destroyed completely for each test case:
abstract class BaseTest extends TestCase
{
/**
* @var \App
*/
protected $app;
public function setUp()
{
$root = dirname(__DIR__) . '/';
$app = $this->app = \App::init([
'root' => $root,
'libraries' => $root . 'vendor/',
'application' => $root . 'app/',
], null, null, false);
//Monolog love to write to CLI when no handler is set
$this->app->logs->debugHandler(new NullHandler());
}
/**
* This method performs full destroy of spiral environment.
*/
public function tearDown()
{
if (class_exists('Mockery')) {
//Mockery defines it's own static container to be destructed
\Mockery::close();
}
//Forcing destruction
$this->app = null;
gc_collect_cycles();
clearstatcache();
}
}
You can pass custom instance of EnvironmentInterface
in order to define separate database credentials and values.
Use HttpTest
with ability to emulate user requests, cookies and sessions:
class IndexTest extends HttpTest
{
public function testSeeWelcome()
{
$response = $this->get('/');
$this->assertSame(200, $response->getStatusCode());
$this->assertContains('Welcome to Spiral Framework', (string)$response->getBody());
$this->assertContains('welcome.dark.php', (string)$response->getBody());
}
}
To manipulate with application services while testing simply bind any specific interface, binding or class to your mock object:
$this->app->container->bind(MyService::class, $myServiceMock);
//...
You can mock database to test your application code in more realisting environment. The nesessary change is to point your target database to another driver (usually runtime SQLite). Be aware, that in this case your tests might take much longer to execute.
public function setUp()
{
$root = dirname(__DIR__) . '/';
$app = $this->app = \App::init([
'root' => $root,
'libraries' => $root . 'vendor/',
'application' => $root . 'app/',
], null, null, false);
//Replace default database
$this->app->dbal->addDatabase(new Database(
$this->app->dbal->driver('runtime'),
'default',
'tests_'
));
//Monolog love to write to CLI when no handler is set
$this->app->logs->debugHandler(new NullHandler());
//Schemas and seeds
$this->app->console->run('orm:schema', ['-alter'=>true]);
$this->app->console->run('app:seed');
}
You can destroy or empty database in tearDown method.
In order to replace application bootloaders list in your tests create App child with desired value:
class TestApplication extends App
{
const LOAD = []; //Bootloads nothing, manual initialization is required
}