I seem to be having a problem with fixtures in Yii. The problem seems to be the following,
public $fixtures=array('projects'=>'Project');
The model Project exists and I have the fixtures in a file name tbl_project.php in the fixtures folder of tests and my table name is called tbl_project. Inside the fixtures file is the following.
return array(
'project1' => array(
'name' => 'Test Project 1',
'description' => 'This is test project 1',
'create_time' => '',
'create_user_id' => '',
'update_time' => '',
'update_user_id' => '',
),
'project2' => array(
'name' => 'Test Project 2',
'description' => 'This is test project 2',
'create_time' => '',
'create_user_id' => '',
'update_time' => '',
'update_user_id' => '',
),
'project3' => array(
'name' => 'Test Project 3',
'description' => 'This is test project 3',
'create_time' => '',
'create_user_id' => '',
'update_time' => '',
'update_user_id' => '',
),
);
This is actually from the book "Agile Web Application Development with Yii". When I run the test case I get the following with no test result information.
PHPUnit 3.6.10 by Sebastian Bergmann.
Configuration read from ETC/protected/tests/phpunit.xml
If I remove the fixtures array from the top I get the following.
Time: 0 seconds, Memory: 9.25Mb
There was 1 error:
1) ProjectTest::testRead
Exception: Unknown method 'projects' for class 'ProjectTest'.
Which obviously makes sense. I dont know what Im doing wrong.
Make sure the test class looks like this
class ProjectTest extends CDbTestCase{
protected $fixtures = array(
'projects' => 'Project',
);
public function testRead(){
$receivedProject = $this->projects('Project1');
$this->assertTrue($receivedProject instanceof Project);
$this->assertEquals($receivedProject->name,'test 1');
}
...`
Check the fixture configuration in protected/config/test.php ... Should look like ...
...
'components'=>array(
'fixture'=>array(
'class'=>'system.test.CDbFixtureManager',
),
'db'=>array(
'connectionString' =>'mysql:host=localhost;dbname=your_db_name',
'emulatePrepare' => true,
'username' => 'username',
'password' => 'passwd',
'charset' => 'utf8',
),
....
Ultimately check the permissions on the fixture file making sure it can be read
Also be sure you are calling parents setUp() method in your own setUp()
class SomeTest extends CDbTestCase {
public $fixtures = array(
'somes' => 'Some',
);
protected function setUp() {
parent::setUp();
// your code....
}
// your tests .......................
}
Is your test class deriven from CDbTestCase instead of CTestCase?
your Test Class should look something like this:
class ProjectTest extends CDbTestCase{
protected $fixtures = array(
'projects' => 'Project',
);
public function testRead(){
$receivedProject = $this->projects('Project1');
$this->assertTrue($receivedProject instanceof Project);
$this->assertEquals($receivedProject->name,'test 1');
}
class ProjectTest extends CDbTestCase
{
public function testCreate()
{
//CREATE a new Project
$newProject=new Project;
$newProjectName = 'Test Project Creation';
$newProject->setAttributes(array(
'name' => $newProjectName,
'description' => 'This is a test for new project creation',
'createTime' => '2009-09-09 00:00:00',
'createUser' => '1',
'updateTime' => '2009-09-09 00:00:00',
'updateUser' => '1',
)
);
$this->assertTrue($newProject->save(false));
//READ back the newly created Project to ensure the creation worked
$retrievedProject=Project::model()->findByPk($newProject->id);
$this->assertTrue($retrievedProject instanceof Project);
$this->assertEquals($newProjectName,$retrievedProject->name);
}
public function testRead()
{
$retrievedProject = $this->projects('project1');
$this->assertTrue($retrievedProject instanceof Project);
$this->assertEquals('Test Project 1',$retrievedProject->name);
}
public function testUpdate()
{
$project = $this->projects('project2');
$updatedProjectName = 'Updated Test Project 2';
$project->name = $updatedProjectName;
$this->assertTrue($project->save(false));
//read back the record again to ensure the update worked
$updatedProject=Project::model()->findByPk($project->id);
$this->assertTrue($updatedProject instanceof Project);
$this->assertEquals($updatedProjectName,$updatedProject->name);
}
public function testDelete()
{
$project = $this->projects('project2');
$savedProjectId = $project->id;
$this->assertTrue($project->delete());
$deletedProject=Project::model()->findByPk($savedProjectId);
$this->assertEquals(NULL,$deletedProject);
}
public function testGetUserOptions()
{
$project = $this->projects('project1');
$options = $project->userOptions;
$this->assertTrue(is_array($options));
$this->assertTrue(count($options) > 0);
}
public $fixtures=array(
'projects'=>'Project',
'users'=>'User',
'projUsrAssign'=>':tbl_project_user_assignment',
);
}
make sure that setup come with its parent
<i>public function setUp() {
parent::setUp();
}</i>
Related
I'm just wondering how you'd mock a service in Symfony.
This is what I've ended up with so far and it's not working as expected. I expect the getVenuesData() method from the NetballFeedService to dump the mocked data in the test (I've set a DD in the command). But when I run the test, it dumps the real time data being pulled from the NetballFeedService.
Test:
public function it_imports_venues(): void
{
$kernel = self::bootKernel();
$netballAPIMock = $this->createMock(NetballFeedService::class);
$netballAPIMock->method('getVenuesData')->willReturn([
800 => ['name' => 'Venue 1', 'location' => 'MEL'],
801 => ['name' => 'Venue 2', 'location' => 'ADE']
]);
$this->getContainer()->set('netballAPI', $netballAPIMock);
$container = $kernel->getContainer();
$container->set('netballAPI', $netballAPIMock);
$application = new Application($kernel);
$command = $application->find('app:feed:import-venues');
$commandTester = new CommandTester($command);
$commandTester->execute([]);
$commandTester->assertCommandIsSuccessful();
}
Command being tested:
protected static $defaultName = 'app:feed:import-venues';
public function __construct(
private readonly NetballFeedService $netballFeedService,
private readonly VenueService $venueService
)
{
parent::__construct();
}
protected function execute(InputInterface $input, OutputInterface $output): int
{
$data = $this->netballFeedService->getVenuesData();
dd($data);
$this->venueService->updateVenuesDataFromFeed($data);
return 0;
}
Class method expected to return mocked data:
public function getVenuesData(): array
{
$response = $this->client->request('GET', self::FIXTURES_URL);
$rawData = json_decode($response->getBody()->getContents(), true);
$rounds = $rawData['data']['results'];
$parsedVenuesData = [];
foreach ($rounds as $round) {
foreach ($round['matches'] as $matches) {
$venueId = $matches['venueId'];
if (array_key_exists($venueId, $matches)) {
continue;
}
$parsedVenuesData[$matches['venueId']] = [
'name' => $matches['venueName'],
'location' => $matches['venueLocation']
];
}
}
ksort($parsedVenuesData);
return $parsedVenuesData;
}
I'm trying to replicate my Laravel test code in Symfony:
/** #test */
public function it_imports_venues()
{
$this->withExceptionHandling();
$this->instance(
NetballAPI::class,
Mockery::mock(NetballAPI::class, function (MockInterface $mock) {
$mock->shouldReceive('getVenuesData')->once()
->andReturn([
800 => [
'name' => 'Venue 1',
'location' => 'MEL'
],
801 => [
'name' => 'Venue 2',
'location' => 'ADE'
],
]);
})
);
$this->artisan('import:venues');
$this->assertDatabaseHas('venues', [
'id' => 800,
'name' => 'Venue 1',
'location' => 'MEL'
]);
$this->assertDatabaseHas('venues', [
'id' => 801,
'name' => 'Venue 2',
'location' => 'ADE'
]);
services_test.yml:
services:
_defaults:
public: true
App\Service\NetballFeedService:
public: true
alias: netballAPI
Just wondering how I can mock the NetballFeedService class in the test instance? Thanks in advance.
I was configuring the service_test.yaml wrong. It should be:
services:
App\Service\NetballFeedService:
public: true
app.netballFeedService:
alias: App\Service\NetballFeedService
public: true
Also, I'm not really used to using YAML files for configs. It's not very readable especially compared to it's PHP file counterpart in this instance. So I'll be experimenting on using both YAML & PHP files for configs/routes etc.
Unable to locate in the SilverStripe Documentation how to have a DataObject Model inject a collection of default records on /dev/build
Anybody able to point me in the right direction
This is what I currently have, and obviously I would like to inject pre-configured options into this aptly named Configuration model for my Module.
class Configuration extends DataObject
{
private static $db = array(
'Option' => 'Varchar',
'Value' => 'Varchar'
);
private static $summary_fields = array(
'Option' => 'Option',
'Value' => 'Value',
);
}
Thanks in advance for any direction/pointers.
UPDATE
I was turned onto SiteConfig by #Barry below
However in following his practice, requireDefaultRecords() is not injecting defaults
Note: I have since revisited /dev/build?flush
class RMSConfiguration extends DataExtension
{
private static $db = array(
'username' => 'Varchar',
'password' => 'Varchar',
'agent_id' => 'Varchar(15)',
'client_id' => 'Varchar(15)',
'testMode' => 'Int(1)',
'timezone' => 'Varchar',
'apiUrl' => 'Varchar(255)'
);
public function updateCMSFields(FieldList $fields)
{
$fields->addFieldsToTab(
"Root.RMSConfig",
array(
TextField::create('username', 'RMS Username'),
TextField::create('password', 'RMS Password'),
TextField::create('agent_id', 'RMS Agent ID'),
TextField::create('client_id', 'RMS Client ID'),
TextField::create('apiUrl', 'API Url'),
CheckboxField::create("testMode", 'Toggle Test Mode'),
DropdownField::create("timezone", 'Timezone', static::$timezones)
)
);
}
public function requireDefaultRecords()
{
parent::requireDefaultRecords();
$arrOptions = array(
'timezone' => 'Australia/Sydney',
'apiUrl' => 'https://api.example.com.au/',
'testMode' => 0
);
foreach ($arrOptions as $strOption => $strValue) {
if (!$configuration = self::get()->filter('Option', $strOption)->first()) {
$configuration = self::create(array( 'Option' => $strOption ));
}
$configuration->Value = $strValue;
$configuration->write();
}
}
/**
* List of timezones supported by PHP >=5.3.x
*
* #var array
*/
public static $timezones = array(
"Africa/Abidjan",
"Africa/Accra",
"Africa/Addis_Ababa",
"Africa/Algiers",
...
...
"Zulu"
);
}
Using the function requireDefaultRecords in the DataObject - this is called during every dev/build.
Note: First check if the option exists to prevent duplicates as this will be called every time you dev build.
class Configuration extends DataObject {
private static $db = array(
'Option' => 'Varchar',
'Value' => 'Varchar'
);
private static $summary_fields = array(
'Option' => 'Option',
'Value' => 'Value',
);
function requireDefaultRecords() {
parent::requireDefaultRecords();
$arrOptions = array(
'Option1' => 'Value1',
'Option2' => 'Value2',
'Option3' => 'Value3',
);
foreach ($arrOptions as $strOption => $strValue) {
if (!$configuration = Configuration::get()->filter('Option',$strOption)->first())
$configuration = Configuration::create(array('Option' => $strOption));
$configuration->Value = $strValue;
$configuration->write();
}
}
}
One final comment is that there is a module for SiteConfig which is used by SilverStripe, most modules and where I would recommend you put configuration values like this instead.
If you do choose SiteConfig then please see the function populateDefaults and documentation for it's use, this is an example...
/**
* Sets the Date field to the current date.
*/
public function populateDefaults() {
$this->Date = date('Y-m-d');
parent::populateDefaults();
}
(if the above is used in an extensions it might need $this->owner->Date instead of $this->Date)
The above function isn't needed if all the values are static, instead it will read them just from this array (again within DataObject)
public static $defaults = array(
'Option1' => 'Value1',
'Option2' => 'Value2'
);
This works on any DataObject as well, but as SiteConfig manages one record and this populates that record once upon creation this is much more convenient for to use instead of requireDefaultRecords.
I have already seen this question:
CakePHP PHPUnit Fixtures Drop Database Table Every Time
Creating multiple fixtures in cakePhp
CakePHP Test Fixtures Drop My Tables Permanently After Running A Test Case
But this links are old I think.
I would like to create test where Im'loading fixtures so test drop tables and create it with records.
My problem is that: Tests drop taboles btu it doesn't recreate it.
This is my model where I'm loading fixtures:
App::uses('Post', 'Model');
class PostTest extends CakeTestCase {
public $fixtures = array('app.post');
public function setUp() {
parent::setUp();
$this->Post = ClassRegistry::init('Post');
}
public function testSetTemplate() {
$this->assertEquals('1', '1');
}
}
And this is my fixture file:
class PostFixture extends CakeTestFixture {
public $import = array('model' => 'Post', 'records' => true);
public $name = 'Post';
public $table = 'posts';
public $fields = array(
'id' => array('type' => 'integer', 'length' => 36, 'key' => 'primary'),
'created' => array('type' => 'datetime'),
'modifed' => array('type' => 'datetime')
);
public $records = array(
array(
'id' => '1',
'created' => '2014-01-17 12:31:41',
'modified' => '2014-07-22 09:50:42'
),
);
}
I have also tried with:
public $import = array('model' => 'Post', 'records' => false);
Same thing tests drop tables but doesn't create it.
I need to create it after drop with my records.
Where s the error? Why tests doesn't recreate it table posts but only drop it?
Thanks
How can I use a core classe in my ORM Model ?
Is working:
protected static $_properties = array(
'id',
'user_id',
'v_key' => array('default' => 'abc' ),
'a_key' => array('default' => 'def' ),
'created_at',
'updated_at'
);
Isn't working:
protected static $_properties = array(
'id',
'v_key' => array('default' => Str::random('alnum', 6) ),
'a_key' => array('default' => Str::random('alnum', 6) ),
'created_at',
'updated_at'
);
Thanks!!
Your actual problem here is that you can't perform function calls when making static assignments in PHP. How to initialize static variables
Ok, I used an observer to do that.
/classes/observer/session.php
<?php
namespace Orm;
use Str;
class Observer_Session extends Observer {
public function after_create(Model $session) {
$session->v_key = Str::random('alnum', 6);
$session->a_key = Str::random('alnum', 6);
}
/classes/model/session.php
To dynamically set default values, you can override the forge method in your session model:
public static function forge($data = array(), $new = true, $view = null, $cache = true)
{
$data = \Arr::merge(array(
'v_key' => \Str::random('alnum', 6),
'a_key' => \Str::random('alnum', 6),
), $data);
return parent::forge($data, $new, $view, $cache);
}
i have multiple php classes
// a Base class
abstract class Base_Page {
protected static $config = array(
'status' => 'int',
);
}
// an inheriting class
class Page extends Base_Page{
protected static $config = array(
'title' => 'varchar',
'description' => 'text',
);
// and one more level of inheritance
class Page_Redirect extends Base_Page {
protected static $config = array(
'href' => 'http://domain.com',
);
}
now id'd like to do this:
$page_redirect = new Page_Redirect();
$page_redirect->getConfig(); // which i assume to be implemented (this is my problem)
// should return:
// array(
// 'status' => 'int',
// 'title' => 'varchar',
// 'description' => 'text',
// 'href' => 'http://domain.com',
// )
Due to the fact that the variable gets overwrote by the extending class a dont't get how to accomplish this. Thanks for your look at it.
You cannot do this with a bare property. It would be much better to use methods instead:
abstract class Base_Page {
protected function getConfig() {
return array('status' => 'int');
}
}
// an inheriting class
class Page extends Base_Page{
protected function getConfig() {
return array(
'title' => 'varchar',
'description' => 'text',
) + parent::getConfig();
}
}
// and one more level of inheritance
class Page_Redirect extends Base_Page {
protected function getConfig() {
return array(
'href' => 'http://domain.com',
) + parent::getConfig();
}
}
Of course now you have lost the ability to get the configuration statically, but it's highly likely that this does not matter. If it does (i.e. you need to know the configuration without having an instance at hand, and it is meaningless to create one on a whim) then the code needs further refactoring.
<?php
// a Base class
abstract class Base_Page {
protected static $config = array(
'status' => 'int',
);
}
// an inheriting class
class Page extends Base_Page {
protected static $config = array_merge(
parent::$config,
array(
'title' => 'varchar',
'description' => 'text',
)
);
}
Try something like this.