phpunit is not populating fixtures in Laravel 4 - sqlite

I'm trying to add a unit testing framework to an already existing Laravel project. I've read the PHPUnit manual and I'm trying to set up a sqlite environment using .xml datasets to populate the test data and a main migration to create the schema but the actual test data does not seem to be populating into the tables.
I started out adding phpunit and dbunit to the composer.json file and updating them. I added vendor/bin to $PATH so the VM will know where to find it.
I then expanding the existing TestCase class with getConnection(), getDataSet() and setUp() which contains
class TestCase extends Illuminate\Foundation\Testing\TestCase {
static private $pdo = null;
private $conn = null;
public function setUp() {
parent::setUp();
Artisan::call('migrate');
$this->seed();
}
public function createApplication() {
$unitTesting = true;
$testEnvironment = 'testing';
return require __DIR__ . '/../../bootstrap/start.php';
}
public function getDataSet() {
parent::getDataSet();
}
public function getConnection() {
if ($this->conn === null) {
if (self::$pdo == null) {
self::$pdo = new PDO('sqlite::memory:');
}
$this->conn = $this->createDefaultDBConnection(self::$pdo, ':memory:');
}
return $this->conn;
}
}
The Illuminate\Foundation\Testing\Testcase I changed to :
abstract class TestCase extends \PHPUnit_Extensions_Database_TestCase {
....
}
This done, I created an XML dataset
<?xml version="1.0" ?>
<dataset>
<table name="a_table">
<column>id</column>
<column>data1</column>
<column>data2</column>
<row>
<value>1</value>
.....
.....
</row>
<row>
.....
</row>
</table>
</dataset>
I used the artisan convert migrations command to create the schema.
Then I wrote my first test.
class ImportantClassTest extends TestCase {
/**
* #author Me
*
*
* Tests the functionality of some function
* #dataProvider ImportantFunctionData();
*/
public function testthisImportantFunction($an_id,$an_amount,$another_amount,$starting_rows,$expected_rows)
{
$this->assertEquals($this->getConnection()->getRowCount('a_table'),$starting_rows);
$result = ImportantClass::ImportantFunction($an_id, $an_amount);
$this->assertEquals($another_amount,$result);
$this->assertEquals($this->getConnection()->getRowCount('a_table'),$expected_rows);
}
public function ImportantFunctionData()
{
return array(
array(1337,1000,180,10,10),
array(1338,3900,900,10,11)
);
}
public function getDataSet()
{
return $this->createXMLDataSet(dirname(__FILE__) . '/_files/ImportantFunctionData.xml');
} }
I added config/testing/database.php :
return array(
'default' => 'sqlite',
'connections' => array(
'sqlite' => array(
'driver' => 'sqlite',
'database' => ':memory:',
'prefix' => '',
)
),
);
When I run the test, the migration occurs to create the db in sqlite memory, but the data does not appear to populate. With the row checking I get this error :
1) ImportantClass::testthisImportantFunction with data set #0 (1337,
1000, 180, 10, 10) PDOException: SQLSTATE[HY000]: General error: 1 no
such table: a_table
and just the result assertion on it's own
1) ImportantClass::testthisImportantFunction with data set #0 (1337,
1000, 180, 10, 10) Failed asserting that 1000 matches expected 180.
So in neither case does it appear that phpunit is populating the fixtures correctly.
Can anyone see where I'm going wrong?

Related

How to write PHP Unit Test for Static Methods

I am very new to PHP Unit Testing. I am trying to create Unit Test for the following function:
$context = $args[0];
if (Subscriber::instance()->isSubscriber()) {
$context['body_class'] .= ' ' . $this->bodyClass;
}
return $context;
Which is very simple which adds classname in array if User is subscriber. Subscriber is class which has has a static instance method which returns true or false.
so far I have written this but I don't think this is correct:
$subscriber = $this->getMockBuilder(Subscriber::class)
->disableOriginalConstructor()
->setMethods(['isSubscriber'])
->getMock();
$subscriber->expects($this->once())
->method('isSubscriber')
->will($this->returnValue(true));
$this->assertInternalType('bool',$subscriber->isSubscriber());
Any help would be appreciated.
Yes, You can mock PHP static methods using PhpUnit together with Mockery!
Case: class to be tested Foo (Foo.php) uses the static method mockMe of the class ToBeMocked.
<?php
namespace Test;
use Test\ToBeMocked;
class Foo {
public static function bar(){
return 1 + ToBeMocked::mockMe();
}
}
ToBeMocked class (ToBeMocked.php)
<?php
namespace Test;
class ToBeMocked {
public static function mockMe(){
return 2;
}
}
The PhpUnit test file (FooTest.php) with mock of static method (using Mockery):
<?php
namespace Test;
use Mockery;
use Mockery\Adapter\Phpunit\MockeryTestCase;
// IMPORTANT: extends MockeryTestCase, NOT EXTENDS TestCase
final class FooTest extends MockeryTestCase
{
protected $preserveGlobalState = FALSE; // Only use local info
protected $runTestInSeparateProcess = TRUE; // Run isolated
/**
* Test without mock: returns 3
*/
public function testDefault()
{
$expected = 3;
$this->assertEquals(
$expected,
Foo::bar()
);
}
/**
* Test with mock: returns 6
*/
public function testWithMock()
{
// Creating the mock for a static method
Mockery::mock(
// don't forget to prefix it with "overload:"
'overload:Geko\MVC\Models\Test\ToBeMocked',
// Method name and the value that it will be return
['mockMe' => 5]
);
$expected = 6;
$this->assertEquals(
$expected,
Foo::bar()
);
}
}
Running this test:
$ ./vendor/phpunit/phpunit/phpunit -c testes/phpunit.xml --filter FooTest
PHPUnit 9.5.4 by Sebastian Bergmann and contributors.
Runtime: PHP 8.0.3
Configuration: testes/phpunit.xml
.. 2 / 2 (100%)
Time: 00:00.068, Memory: 10.00 MB
OK (2 tests, 3 assertions)
You can test (assert) static methods but you can't mock or stub them in PHPunit.
From the documentation:
Please note that final, private, and static methods cannot be stubbed
or mocked. They are ignored by PHPUnit’s test double functionality and
retain their original behavior except for static methods that will be
replaced by a method throwing a
\PHPUnit\Framework\MockObject\BadMethodCallException exception.

Complex serialization

For example, I have two entities: main (parent) entity (for example User) and dependent entity (Post). I want to serialize User entity using JMS Serializer with additional information of its first post date. The post date stored in DB is timestamp int, but I want to serialize it with my helper (just a service) which converts int to sting with some formatting.
Trying to create a virtual_property with method at entity class, but failed to inject my helper into entity class. The only way to solve it for me is to serialize by myself into controller:
public function someAction()
{
$serializedUser = $this->serializeEntity($user);
}
public function serializeEntity(User $user)
{
// JMS serialization
$user = $this->get('jms_serializer')->serialize($user, 'array');
if ($user->getPosts()->count()) {
$post = $user->getPosts()->first();
$user['first_post_date'] = $this->get('my_helper_service')->dateFormat($post->getDate());
}
return $user;
}
NB: this example is synthetic, in the real world I have more complex methods, not just date formatter. But the main idea is the same.
I feel there should be better way to do this.
Dmtry's solution should work perfectly for your case.
An event listener/subscriber is the best solution in this case.
A bit more general solution, that works even with objects and will trigger the whole event system part of the JMS serializer (Dmtry's solution works only with primitives and only for JSON/YAML, not XML), is:
class MyFormatter implements EventSubscriberInterface
{
public static function getSubscribedEvents()
{
return array(
array(
'event' => 'serializer.post_serialize',
'method' => 'onPostSerialize',
'class' => 'YourEntity'
),
);
}
public function __construct(MyFormatter $foermatter)
{
$this->formatter = $formatter;
}
public function onPostSerialize(ObjectEvent $event)
{
$visitor = $event->getVisitor();
$context = $event->getContext();
$timestamp = $event->getObject()->getTimestamp();
$formattedTime = $this->formatter->format($timestamp);
$metadata = new StaticPropertyMetadata('stdClass', 'first_post_date', $formattedTime);
$visitor->visitProperty($metadata, $formattedTime, $context);
}
}
stdClass is ignored by the serializer...
Of course, there is a better way. It's called serialization events.
http://jmsyst.com/libs/serializer/master/event_system
You create event subscriber
my_bundle.serializer_subscriber:
class: MyBundle\Serializer\MyEntitySerializerSubscriber
arguments:
- #bundle.time_formatter
tags:
- { name: jms_serializer.event_subscriber }
And then just add the data you need in your listener
public function myOnPostSerializeMethod(ObjectEvent $event)
{
if (!($event->getObject() instance of YourEntity)) {
return;
}
$timestamp = $event->getObject()->getTimestamp();
$visitor = $event->getVisitor();
$visitor->addData('date', $this->formatter->format($timestamp));
}
P.S. I didn't check the code, so maybe I'm mistaken somewhere with name of methods, but the idea is clear, I hope

Custom Report SilverStripe 3.1

I followed the docs to create a custom report but keep failing to generate the report in the CMS. Has anyone else had this problem? I noticed that with older versions, the config had to include the report, but I see no sign of this in 3.1.
Here is the contents of CustomSideReport.php
class CustomSideReport_Day extends SideReport {
public function title() {
return "Event Calendar";
}
public function records() {
return Page::get()->sort("Title");
}
public function fieldsToShow() {
return array(
"Title" => array("NestedTitle", array("2"))
);
}
}
I have the done the usual dev/build and flush, but still nothing appears.
The documentation has now been updated to correctly show how to make custom site reports.
In SilverStripe 3.1 the class should extend SS_Report instead of SideReport.
Try this:
class CustomSideReport_Day extends SS_Report {
public function title() {
return 'Event Calendar';
}
public function sourceRecords($params = null) {
return Page::get()->sort('Title');
}
public function columns() {
$fields = array(
'Title' => 'Title'
);
return $fields;
}
}
Also note that records() has changed to sourceRecords($params = null) and fieldsToShow() has changed to columns().

How can I bind a Symfony config tree to an object

How would I go about binding a Symfony config tree to a class rather than returning an array?
Using Symfony\Component\Config\Definition\Processor returns an array.
In my case I want the config to be bound to a class so I can use methods to combine parts of the data.
Here is a simple example of my use case. I want the config bound to a class so I can use a method to join table.name and table.version together (my actual use case is more complex, but this is a simple example)
config.yml
db:
table:
name: some_table
version: v2
ConfigurationInterface
class DBConfiguration implements ConfigurationInterface
{
/**
* {#inheritDoc}
*/
public function getConfigTreeBuilder()
{
$treeBuilder = new TreeBuilder();
$rootNode = $treeBuilder->root('db');
$rootNode
->children()
->arrayNode('table')
->children()
->scalarNode('name')->isRequired()->end()
->scalarNode('version')->end()
->end()
->end()
;
return $treeBuilder;
}
}
Class I want to bind the config to
class DB
{
public $table;
public function __construct()
{
$this->table = new Table();
}
}
class Table
{
public $name;
public $version;
/**
* #return string
* Calculate the full table name.
*/
public function getTableName()
{
return $this->name.'-'.$this->version;
}
}
The Symfony Config component doesn't support that.
However, in a Symfony project, this is usually done at the container compile phase. In your bundle's Extension class, you will have access to the configuration tree of your bundle in array form.
You can then take this array and assign it to a service defined in the service container that will create your config object.
This is exactly how DoctrineBundle's configuration class is built:
Abstract services (for the configuration and the factory) are defined in dbal.xml
When loading DoctrineBundle's extension, an instance of the abstract config service is created for each defined connection.
An instance of the abstract factory service is created for each defined connection.
The options array is then passed to the abstract factory service along with the configuration
When creating an instance, the factory then does the necessary transformations.
As far as I know, Symfony has no native support for this, however, you could implement it yourself. You could use subset of Symfony Serializer Component in charge of deserialization, but I think it would be an overkill. Especially since I don't see any PublicPropertyDenormalizer, only GetSetMethodNormalizer (which is denormalizer too). Therefor you would have to either make your config objects have get/set methods or roll PublicPropertyDenormalizer on your own. Possible but it really seems like an overkill and doesn't look like helping much:
Symfony Serializer Component
$array = [
'field1' => 'F1',
'subobject' => [
'subfield1' => 'SF1',
],
];
class MyConfigObject implements Symfony\Component\Serializer\Normalizer\DenormalizableInterface
{
private $field1;
private $subobject;
public function getField1()
{
return $this->field1;
}
public function setField1($field1)
{
$this->field1 = $field1;
}
public function getSubobject()
{
return $this->subobject;
}
public function setSubobject(SubObject $subobject)
{
$this->subobject = $subobject;
}
public function denormalize(\Symfony\Component\Serializer\Normalizer\DenormalizerInterface $denormalizer, $data, $format = null, array $context = array())
{
$obj = new static();
$obj->setField1($data['field1']);
$obj->setSubobject($denormalizer->denormalize($data['subobject'], 'SubObject'));
return $obj;
}
}
class SubObject
{
private $subfield1;
public function getSubfield1()
{
return $this->subfield1;
}
public function setSubfield1($subfield1)
{
$this->subfield1 = $subfield1;
}
}
$normalizer = new \Symfony\Component\Serializer\Normalizer\GetSetMethodNormalizer();
$obj = (new MyConfigObject())->denormalize($normalizer, $array);
Native PHP Way
Imo this is a lot easier than above as Symfony Serializer wasn't really ment for that.
$array = [
'field1' => 'F1',
'subobject' => [
'subfield1' => 'SF1',
],
];
trait Denormalizable
{
public function fromArray($array)
{
foreach ($array as $property => $value) {
if (is_array($value)) {
if ($this->$property instanceof ArrayDenormalizableInterface) {
$this->$property->fromArray($value);
} else {
$this->$property = $value;
}
} else {
$this->$property = $value;
}
}
}
}
interface ArrayDenormalizableInterface
{
public function fromArray($array);
}
class MyConfigObject implements ArrayDenormalizableInterface
{
use Denormalizable;
public $field1;
public $subobject;
public function __construct()
{
$this->subobject = new SubObject();
}
}
class SubObject implements ArrayDenormalizableInterface
{
use Denormalizable;
public $subfield1;
}
$myConf = new MyConfigObject();
$myConf->fromArray($array);
Whatever way you choose, you can now just take array returned from symfony processor and turn it into a config object you need.

Not able to call dependent test cases

I am writing the unit tests to test a Model class.
First I have a testAddStudent() test case that adds some data to db.
Then I have another test case to retrieve the record I just added.
The code I have looks like the following:
class Model_STest extends PHPUnit_Framework_TestCase {
protected $_student;
public function setUp() {
error_log("Entered setup");
parent::setUp();
$this->_student = new Application_Model_Student();
}
public function testInit() {
error_log("Entered testInit");
}
public function testAddStudent() {
error_log("Entered testAddStudent");
$testData = array(
'name' => 'abc',
'teacher' => 'amyac',
'start_date' => '2012_08_06'
);
$result = $this->_student->addStudent($testData);
error_log("result is ".print_r($result, true));
$this->assertGreaterThan(0, $result);
}
/**
* #depends testAddStudent
*/
public function testGetStudent($result) {
error_log("Entered testGetStudent, finding student id: $result");
$resultx = $this->_student->getStudent($result);
$this->assertEquals($result, $resultx);
}
}
However, when I run the phpunit test (using command line), The logs show me that the student id being searched is 0. Whereas the testAddStudent is returning me the student id as a non-zero value.
What am I doing wrong?
I have
PHPUnit 3.6.11 by Sebastian Bergmann.
Any help is greatly appreciated.
Thanks!
You should return $result from your testAddStudent() function.
(The returned value from the depended-on function is passed to depending function.)
You might also consider doing the same with your Application_Model_Student instance, instead of using a protected class variable. Here is your example rewritten to show that. (I used a dummy Application_Model_Student that does just enough to pass the test.)
class Application_Model_Student{
private $d;
function addStudent($d){$this->d=$d;return 1;}
function getStudent($ix){return $ix;}
}
//----------------------
class Model_STest extends PHPUnit_Framework_TestCase {
public function testAddStudent() {
error_log("Entered testAddStudent");
$testData = array(
'name' => 'abc',
'teacher' => 'amyac',
'start_date' => '2012_08_06'
);
$student = new Application_Model_Student();
$result = $student->addStudent($testData);
error_log("result is ".print_r($result, true));
$this->assertGreaterThan(0, $result);
return array($student,$result);
}
/**
* #depends testAddStudent
*/
public function testGetStudent($data) {
list($student,$result)=$data;
error_log("Entered testGetStudent, finding student id: $result");
$resultx = $student->getStudent($result);
$this->assertEquals($result, $resultx);
}
}
P.S. Note the implementation I used for getStudent to get it to pass! I imagine this is not the test you intended to do.

Resources