Open Laykou opened 9 years ago
I see the codeception.yml
- it should somehow work with Fixtures.
actor: Tester
paths:
tests: tests
log: tmp/tests
data: tests/Fixture
helpers: src/TestSuite/Codeception
settings:
bootstrap: bootstrap.php
colors: false
memory_limit: 1024M
@Laykou you're right, it does!
I tried leveraging as much of the current Cake\TestSuite
as possible. I still don't have much documentation but it is coming.
The 3 suites are VERY different. I will only discuss the 'Functional' and 'Unit' ones here, acceptance testing doesn't use fixtures per se - it requires a full-fledged environment to make HTTP requests to and that's a different setup.
For functional tests, they use the Cake\Codeception\Helper
module which allows you to load fixtures the same way you are used to in cake tests:
$I->loadFixtures([
'app.users',
'app.posts',
]);
It also adds a couple helper functions you can find in the Cake\Codeception\Helper\DbTrait
.
Unit tests, while also using the Cake\Codeception\Helper
can just be extending the default Cake\TestSuite\TestCase
or Cake\TestSuite\IntegrationTestCase
and they will function just like they used to.
It's also good to add that you can create a Cake\TestSuite\Codeception\FunctionalHelper::_before(Codeception\TestCase $test)
method that will take care of loading all of your application's fixtures before every test:
class FunctionalHelper extends Module
{
public function _before(Test $test)
{
$I = $this->getModule('Cake\Codeception\Helper');
$I->loadFixtures([
'app.companies',
'app.posts',
]);
}
}
In CakePHP, we've been used to have Cake\TestSuite\TestCase::$autoFixtures
and Cake\TestSuite\TestCase::$dropTables
- those are also available in the Codeception integration. You can set them globally for all your tests in a suite by adding the following to your suite's configuration file:
modules:
config:
Cake\Codeception\Helper:
autoFixtures: false
dropTables: true
or within any test (before the call to amOnPage()
:
$I->autoFixtures = false;
$I->dropTables = true;
Defaults are TRUE
for $autoFixtures
and FALSE
for $dropTables
.
That's it for now. While I can still explain a lot more, document how to use the default db dumps Codeception supports, etc. I believe this will at least get you going without adding more complexity to stuff until we have a better documentation written (I suck at that, sorry).
Let me know if you have any other questions.
Thank you very much for this quick guide. Codeship.com runs a PHP server on 127.0.0.1:8000 so the Acceptance tests have chance to work I guess. The database just needs to be prepared somehow also with data.
@jadb Do you have a experience with third-party testing services? What setup do you recommend? It doesn't have to be the codeship, but as I see it is free also for private repos on Github.
@Laykou, definitely. Acceptance tests can run. The only thing is that preparing data for those is slightly different - it's a full-fledged application. So depending on how you 'build' the application, you'll need to build that on the test environment, dump the schema (as u do in production) or using migrations, insert some data (or use a plugin to generate some, i.e. gourmet/faker
), configure the Acceptance.suite.dist.yml
to use the test webserver and you're good to go.
As for third-party services, I personally preferred CircleCI over Codeship (which I tried about 8 months ago). They recently allowed private repos (with limited build servers though) also, might want to check them out.
I got it thanks. So how should I prepare the schema and data? Where to put these information? The best would be to create the schema in one file, and then insert the default data in *.yml
file like:
users:
1:
id: 2
username: test
password: **hash**
2:
id: 2
username: admin
password: **hash**
articles:
1:
id: 1
user_id: 1
title: CakePHP
content: Something
but currently any solution is good. Even the *.sql
dump file is OK for me.. The question is where to put the file and in what format so that the tests can run automatically on any enviroment?
The Codeship (and I the CircleCI is similiar) allows me to setup the server in the initial script that is being run before the testing:
nohup bash -c "php -S 127.0.0.1:8000 2>&1 &" && sleep 1; cat nohup.out
I can setup some env variable like: APP_ENV=codeship
and in my cake bootstrap.php
I can overwrite the default
connection:
if (in_array(env('APP_ENV'), ['codeship', 'circleci'])) {
ConnectionManager::alias(env('APP_ENV'), 'default');
}
and add the connection in app.php:
// EDIT: Put this into your app.default.php
as the app.php
file is not synced via GIT and is automatically created from app.default.php
if missing.
'Datasources' => [
'codeship' => [
// https://codeship.com/documentation/databases/postgresql/#section-2
'driver' => 'Cake\Database\Driver\Postgres',
'username' => env('PG_USER'),
'password' => env('PG_PASSWORD'),
'database' => 'test'
],
'circleci' => [
// https://circleci.com/docs/environment#databases
'driver' => 'Cake\Database\Driver\Postgres',
'username' => 'ubuntu',
'password' => null,
'database' => 'circle_test'
]
]
Then I can setup the tests\Acceptance.suite.yml
:
env:
codeship:
modules:
config:
PhpBrowser:
url: 'http://127.0.0.1:8000'
circleci:
modules:
config:
PhpBrowser:
url: 'http://127.0.0.1:8000'
and run the tests with
vendor\bin\codecept run --env codeship
So to repeat the question: where to put the schema and default test data so that they are loaded before testing?
BTW: If you find my solution good you can take it to the documentation. I still haven't tested but I'll give the feedback if it works or not.
Nice findings @Laykou.
As a matter of fact, you've got a lot of it correctly. I, so far, have only used it with fixtures but can totally see why people would prefer using an SQL dump at times and that is also meant to be supported (haven't tested it yet though).
SQL schema/data dumps are supported by Codeception out of the box. All you need to do is to require the Db
module in your Acceptance
suite config and setup the DSN config and point it to your dump file. Here's an example:
modules:
enabled:
- Db
config:
Db:
dsn: 'PDO DSN HERE'
user: 'root'
password:
dump: tests/Fixture/your-dump-name.sql
Hoping this helps. Let me know if you have more questions.
I figured out that I cannot use the Db
module in Codeception, becuase the credentials are stored in env
. I could possibly set
config:
Db:
dsn: 'PDO DSN HERE'
user: __PG_USER__
password: __PG_PASSWORD__
dump: tests/Fixture/your-dump-name.sql
And then use some pre-test script which will overwrite the credential placeholders
// Create as PrepareTest shell command and run in codeship before the testing: bin/cake prepare_test
$path = 'tests/Acceptance.suit.yml'
$config = file_get_contents($path);
str_replace('__PG_USER__', env('__PG_USER__'), $config);
str_replace('__PG_PASSWORD__', env('__PG_PASSWORD__'), $config);
file_put_contents($path, $config);
But using the dump.sql
file is not a clean solution.
Just for the record: I did all the steps described in my previous comments, but instead of using the dump.sql
file which was hard to export from MSSQL and use in PostgreSQL I use the Fixtures. In the tests/Acceptance/bootstrap.php
I will load all the fixtures, which will update the schema and setup default data for selected tabels.
// tests/Acceptance/bootstrap.php
<?php
use Cake\TestSuite\Fixture\FixtureManager;
use Cake\TestSuite\TestCase;
class FakeTestSuite extends TestCase
{
// Here you can load all the tables/fixtures. See the CakePHP 3.0 documentation
public $fixtures = ['app.users'];
}
$manager = new FixtureManager();
$fakeTestSuite = new FakeTestSuite();
$manager->fixturize($fakeTestSuite);
// Changing the connection type manually
$loaded = $manager->loaded();
foreach ($loaded as $fixture) {
// Change this to the connection name in your config/app.default.php you want to use
if (in_array(env('APP_ENV'), ['codeship', 'circleci'])) {
$fixture->connection = env('APP_ENV');
}
}
$manager->load($fakeTestSuite);
Using the fixtures makes the code much cleaner and you can use them to setup Acceptance tests and also Unit tests.
One note: you have to define the connection in the app.default.php
, because your app.php
file is not synchronized via GIT and if there is no app.php
file, Cake creates one from the app.default.php
. Just do not use any sensitive data there.
I have tested this and it WORKS!
On circle you can create file circle.yml
in the root with this:
machine:
php:
version: 5.6.2
environment:
APP_ENV: circleci
dependencies:
override:
- composer install --prefer-dist --no-interaction
- php vendor/codeception/codeception/codecept build
- nohup bash -c "php -S 127.0.0.1:8000 2>&1 &" && sleep 1; cat nohup.out
test:
override:
- phpunit
- php vendor/codeception/codeception/codecept run --env circleci
On codeship you can configure:
# Modify your Setup Commands
phpenv local 5.5
composer install --prefer-source --no-interaction
php vendor/codeception/codeception/codecept build
nohup bash -c "php -S 127.0.0.1:8000 2>&1 &" && sleep 1; cat nohup.out
# Modify your Test Commands
phpunit
php vendor/codeception/codeception/codecept run --env codeship
I modified the snippets in my previous comments to work with codeship and circle. So keep in mind that you need to update these files:
config/app.default.php
- setup testing db connectionsconfig/bootstrap.php
- alias the default connection tests/Acceptance.suite.yml
- set the PHP browser addresstests/Acceptance/bootstrap.php
- load the database from fixturescircle.yml
- setup tests for CircleCIHopefully someone will find this useful.
Thanks for sharing! :+1:
Still in the process of writing documentation. If you'd like to help, let me know.
Could you please explain (also in documentation) how should I prepare the database?
I would like to run the tests also on third party continous integration tool like https://codeship.com
Where/how should I prepare the data and schema? Or is it connected with cake's fixtures?
In Rails I am able to load the schema
bundle exec rake db:schema:load
. In cake there is no schema lock file, but in the fixtures it can be defined from scratch or copied from existing database. But on third party server this is not handy because there is no existing database. This schema lock file could be refreshed after every migration. This is how it works in Rails if I'm correct.What do you think and how would you solve this? Thanks alot.