YII2 Codeception - create fixture. [Error] Class 'tests\fixtures\UserFixture' not found - yii2

I'm using YII2 2.0.10, basic. It seems that it don't use yii-codeception module anymore. So documentation from this page is not actual:
http://www.yiiframework.com/doc-2.0/guide-test-fixtures.html
My problem is that I can't load fixture to my test.
I'm using such way:
tests\unit\models\UserTest.php
<?php
namespace tests\models;
use app\models\User;
use tests\fixtures\UserFixture;
class UserTest extends \Codeception\Test\Unit
{
public function testFindUserById()
{
// load fixtures
$this->tester->haveFixtures([
'user' => [
'class' => UserFixture::className(),
// fixture data located in tests/_data/user.php
'dataFile' => codecept_data_dir() . 'user.php'
]
]);
// get first user from fixtures
$this->tester->grabFixture('user', 0);
...
tests\fixtures\UserFixture.php
namespace tests\fixtures;
use yii\test\ActiveFixture;
class UserFixture extends ActiveFixture
{
public $modelClass = 'dektrium\user\models\User';
}
And have some data returned from tests\fixtures\data\user.php
After vendor/codeception/base/codecept run I get
2) UserTest: Find user by id
Test tests/unit/models/UserTest.php:testFindUserById
[Error] Class 'tests\_fixtures\UserFixture' not found
#1 tests\models\UserTest->testFindUserById
What I'm doing wrong?

Related

Yii2 codeception dataFile fixture can't be found

I am trying to run simple test and insert two record in db via fixture dataFile.
What I get is :
[ReflectionException] Class C:\xampp\htdocs\codeception\frontend\tests/_data\user.php does not exist
The file is obviously there. My UserTest.php looks like this:
<?php
class UserTest extends \Codeception\Test\Unit
{
public function _fixtures()
{
return [
'class' => \frontend\tests\fixtures\UserFixture::className(),
'dataFile' => codecept_data_dir() . 'user.php'
];
}
public function testValidation()
{
$user = new \common\models\User();
$user->setUsername(null);
$this->assertFalse($user->validate(['username']));
$user->setUsername('aaaaaaaaaaaaaaaaaaaaaaaaaa');
$this->assertFalse($user->validate(['username']));
$user->setUsername('toma');
$this->assertTrue($user->validate(['username']));
}
public function testIfUserExist()
{
$this->tester->seeRecord('user', ['name' => 'Toma']);
}
}
I saw the linux like forward slash in the error but don't know how to change it. Not sure if this is the problem because I had the same path with some images and it was fine then. What can cause this ? Thank you!
You're using seeRecord() in a wrong way. First argument needs to by class name, including namespace, so you should use it like this:
$this->tester->seeRecord(\frontend\models\User::class, ['name' => 'Toma']);

How do I call `grabFixture()` method from within `ApiTester instance in Yii2?

I am building an API in Yii2 2.0.14 and running tests with Codeception. Examples in the tutorial* show that I can call fixtures like so:
$profile = $I->grabFixture('profiles', 'user1');
However this doesn't seem to be available in my test class here:
<?php
namespace frontend\tests\api;
use frontend\tests\ApiTester;
class DemoCest
{
public function _fixtures()
{
return [
'users' => [
'class' => UserFixture::className(),
// fixture data located in tests/_data/user.php
'dataFile' => codecept_data_dir() . 'user.php'
],
];
}
public function demo(ApiTester $I)
{
$users = $I->grabFixture('users');
$I->wantTo('perform actions and see result');
$I->haveHttpHeader('Content-Type', 'application/x-www-form-urlencoded');
$I->sendPOST('/user/test', ['name' => 'davert', 'email' => 'davert#codeception.com']);
$I->seeResponseCodeIs(\Codeception\Util\HttpCode::OK); // 200
$I->seeResponseIsJson();
$I->seeResponseContainsJson(['message' => 'test OK']);
}
}
I have seen that you need to add fixtures to frontend/tests/api-suite.yml but Codeception is throwing an exception when I do that
PHP Notice: Undefined index: tests in
/var/www/vendor/codeception/base/src/Codeception/Command/Run.php on
line 389
I am completely lost.
actor: ApiTester
modules:
enabled:
- Yii2:
part: [orm, email, fixtures]
- \frontend\tests\Helper\Api
- REST:
url: http://securedata.test/api/v1
depends: PhpBrowser
part: Json
Can anyone lead me in the right direction?
tutorial - http://www.yiiframework.com/doc-2.0/guide-test-fixtures.html
Add to your suite configuration, you haven't defined the tests path in the codeception.yml under paths.
If you look into the line the error points to it will take you to the line inside the matchSingleTest function
in your case
list(, $suite, $test) = $this->matchTestFromFilename($suite, $config['paths']['tests']);
in which it gives tests as undefined index for the $config['paths'] array, which if you backtrack parses the codeception.yml to the $config,
You are using an older version of Yii 2.0.14 which may have the missing section from the execute() see this ISSUE
So add tests directory as . and make sure your codeception.yml is in the /tests root.
see the following
paths:
tests: .

zf2 Zend\ServiceManager\Exception\ServiceNotCreatedException

I spent half day to resolve this issue with no success.
I'm doing a setup in EC2, centos 6/64 bit. LAMP installed. On another hosting, my zf2 solution it work fine, so I've searched issue in php modules installed also (list at the end).
This error happen when zf2 try to get an instance of my custom service, also with wasabi mail.
\zend\config\application.config.php
'config_glob_paths' => array(
'./config/autoload/{,*.}{global,local}.php',
),
\zend\config\autoload\global.php
'service_manager' => array(
'factories' => array(
'Zend\Db\Adapter\Adapter' => 'Zend\Db\Adapter\AdapterServiceFactory',
'Zend\CustomLogger' => function ($sm) {
$auth = $sm->get('zfcuser_auth_service');
$customLogger = new \Application\Service\CustomLogger(
$sm->get('Request'),
$sm->get('ZendLog'),
new \Zend\Session\SessionManager(),
$auth->getIdentity(), // $user
$sm->get('Mail'));
return $customLogger;
},
controller
<?php
namespace Foo\Controller;
use Zend\Mvc\Controller\AbstractActionController;
use Zend\View\Model\ViewModel;
use Doctrine\ORM\EntityManager;
use MyProject\Proxies\__CG__\OtherProject\Proxies\__CG__\stdClass;
class FooController extends AbstractActionController
{
protected $customLogger;
private function getCustomLogger()
{
if (null === $this->customLogger) {
$this->customLogger = $this->getServiceLocator()->get('Zend\CustomLogger');
}
return $this->customLogger;
}
public function indexAction()
{
$this->getCustomLogger();
$this->customLogger->controllerLog("ENTER IN Foo\Controller\FooController\index", "info");
// .... other code
}
}
Error
Zend\ServiceManager\Exception\ServiceNotCreatedException
File:
/var/www/solutions/mysolution/zend/vendor/zendframework/zendframework/library/Zend/ServiceManager/ServiceManager.php:930
Message:
An exception was raised while creating "Zend\CustomLogger"; no instance returned
PHP modules installed
bz2.so curl.so fileinfo.so iconv.so mbstring.so mysqlnd.so pdo_sqlite.so shmop.so sqlite3.so sysvshm.so xmlreader.so xsl.so
calendar.so dom.so ftp.so intl.so mysqlnd_mysqli.so pdo_mysqlnd.so phar.so simplexml.so sysvmsg.so tokenizer.so xml.so zip.so
ctype.so exif.so gettext.so json.so mysqlnd_mysql.so pdo.so posix.so sockets.so sysvsem.so wddx.so xmlwriter.so
Extension enabled in PHP ini
extension=/usr/lib64/php/5.5/modules/php_bz2.so
extension=/usr/lib64/php/5.5/modules/php_curl.so
extension=/usr/lib64/php/5.5/modules/php_fileinfo.so
extension=/usr/lib64/php/5.5/modules/php_gd2.so
extension=/usr/lib64/php/5.5/modules/php_intl.so
extension=/usr/lib64/php/5.5/modules/php_mbstring.so
extension=/usr/lib64/php/5.5/modules/php_mysql.so
extension=/usr/lib64/php/5.5/modules/php_mysqli.so
extension=/usr/lib64/php/5.5/modules/php_openssl.so
extension=/usr/lib64/php/5.5/modules/php_pdo_mysql.so
extension=/usr/lib64/php/5.5/modules/php_soap.so
extension=/usr/lib64/php/5.5/modules/php_xmlrpc.so
extension=/usr/lib64/php/5.5/modules/php_xsl.so
So simple solution... permission on log directory and some others directory are wrong. Restore the correct permissione, user and group on directory (e.g. data/logs, data/cache...)

how to create own traits migration in yii2

This is a default code for migration
<?php
use yii\db\Schema;
use yii\db\Migration;
class m150101_185401_create_news_table extends Migration
{
public function up()
{
$this->createTable('news', [
'id' => Schema::TYPE_PK,
'title' => Schema::TYPE_STRING . ' NOT NULL',
'content' => Schema::TYPE_TEXT,
]);
}
public function down()
{
$this->dropTable('news');
}
}
here TYPE_TEXT is a predefined trait ,
so how i can create my own trait for example
int(11) Not NULL unsigned to unsignedInt is there any way to create own traits.
For this you can define your personalSchemaBuilderTraits in a proper namespace and the recall this in your code
look at this yii2 doc http://www.yiiframework.com/doc-2.0/yii-db-schemabuildertrait.html
https://github.com/yiisoft/yii2/blob/master/framework/db/Migration.php
In Migration.php you can easly view in the firt line the call for use ....
In yii\db\SchemaBuilderTrait you can see the functions for settinge the value of the several column data type. This is the preferred method for create column from version 2.0.6

How to use the global.php/local.php configs in the getConfig() of a module in a Zend Framework 2 application?

In a ZF2 application I have some cofigs, that: 1. need to be different dependening on the environment; 2. are specific for a concrete module. I'm curently using it like here described:
global.php & local.php
return array(
...
'modules' => array(
'Cache' => array(
'ttl' => 1, // 1 second
)
)
...
);
Module class
Module {
...
public function getServiceConfig() {
try {
return array (
'factories' => array(
'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
return new MemcachedOptions(array(
'ttl' => $this->getConfig()['modules']['Cache']['ttl'],
...
));
},
...
)
);
}
...
}
...
}
It's working fine, but I believe, that the module specific settings should be accessed over one central place in the module -- the getConfig() method of the Module class. Like this:
class Module {
public function getConfig() {
$moduleConfig = include __DIR__ . '/config/module.config.php';
$application = $this->getApplicationSomehow(); // <-- how?
$applicationModuleConfig = $application->getConfig()['modules'][__NAMESPACE__];
$config = array_merge($moduleConfig, $applicationModuleConfig);
return $config;
}
...
public function getServiceConfig() {
try {
return array (
'factories' => array(
'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
return new MemcachedOptions(array(
'ttl' => $serviceManager->get('Config')['modules']['Cache']['ttl'],
...
));
},
...
)
);
}
...
}
...
}
The problem is, that I don't get, how to access the global.php/local.php configs in the getConfig() of a module. How can I do it?
Every single configuration of every single loaded Module will be merged into one single config. Namely this would be:
$serviceManager->get('config');
The reason behind (global|local).config.php is merely for usage purpose. Global configuration files should always be deployed. Local configuration files however should only be deployed as distributionables, alias local.config.php.dist.
Distributionals will not be loaded, no matter where they are places. However common notion of ZF2 is to copy the distributionables into the /config/autoload-directory of the ZF2 Application and rename them to local.config.php
One example:
// YourModule/config/module.config.php
return array(
'key' => 1337
);
// YourModule/config/local.yourmodule.php.dist
return array(
'key' => 7331
);
Now when you publish / deploy your application, only module.config.php will be used. If someone wants to change the configuration of your Module, they would never touch module.config.php, as this file would constantly be overwritten when your module will be updated.
However what people can do is to copy:
YourModule/config/local.yourmodule.php.dist
to
/config/autoload/local.yourmodule.php
And change the config values inside this local configuration.
To understand:
You should always configure your module as best as possible for a LIVE-Scenario.
If you have environment-specific needs, overwrite this config using a local-config
local configs are never deployed automatically, this is a manual task needing to be done from inside the environment itself
Hope this got a little more clear
Ultimately:
configure your module for a LIVE-Scenario
On your development machine create a /config/autoload/mymodule.local.php and overwrite your ttl with it's development value
LoadOrder:
The last interesting part, which i have completely forgotten about, would be the load order of the configuration files. As all files are merged, this is important to note!
First to load is /config/application.config.php
Second to load would be each Modules /modules/{module}/config/module.config.php *
Last but not least the autoloadable files will be loaded /config/autoload/{filename}.php
asterix It is actually NOT module.config.php which is called, but rather the Module-classes configuration functions. Mainly these are:
getConfig()
getServiceConfig()
getViewHelperConfig()
ultimately everything under Zend\ModuleManager\Feature\{feature}ProviderInterface
If i understand this part of the ConfigListener correctly, then getConfig() will be called first and all of the specialiced {feature}ProviderInterfaces will overwrite the data of getConfig(), but don't take this for granted, it would need a check!
You're not supposed to access other Modules setting in your Module#getConfig(). If you rely on other configuration, that CAN ONLY BE for service purposes. Ergo you'd rely on Module#getServiceConfig() and inside the factories you do have access to the ServiceManagerand access your configs with $serviceManager->get('config');. (see Sam's comment)
The loading order of the configs is by default:
/config/application.config.php, that is the initial config file; not for module configs; here is the filename pattern for the config files to load defined ('config_glob_paths' => array('config/autoload/{,*.}{global,local}.php')).
{ModuleNamespace}\Module#getConfig() (e.g. Cache\Module#getConfig()), that by convention should load its /module/{ModuleNamespace}/config/module.config.php;
/config/autoload/global.php, that should not contain any module specific configs (see below);
/config/autoload/local.php, that contains environment specific settings also should not contain any module specific configs (see below); it should not versioned/deployed;
/config/autoload/{ModuleNamespaceLowerCased}.local.php (e.g. cache.local.php), that contains only the module AND environment specific settings and should not be versioned/;
For the Cache module above there can be following config files:
/module/Cache/config/module.config.php -- a complete set of module configs; loaded by Cache\Module#getConfig()
/module/Cache/config/cache.local.php.dist -- an example for /config/autoload/cache.local.php
/config/autoload/cache.local.php -- environment specific module configs
The setting ttl can be accessed from any place, where one has access to the Service Locator. For example in factory methods of Cache\Module#getServiceConfig()
class Module {
public function getConfig() {
$moduleConfig = include __DIR__ . '/config/module.config.php';
$application = $this->getApplicationSomehow(); // <-- how?
$applicationModuleConfig = $application->getConfig()['modules'][__NAMESPACE__];
$config = array_merge($moduleConfig, $applicationModuleConfig);
return $config;
}
...
public function getServiceConfig() {
try {
return array (
'factories' => array(
'Zend\Cache\Adapter\MemcachedOptions' => function ($serviceManager) {
return new MemcachedOptions(array(
'ttl' => $serviceManager->get('Config')['ttl'],
...
));
},
...
)
);
}
...
}
...
}
For futher information about how configs are managed in ZF2 see Sam's answer and blog article.