I spent a lot of time by searching where is the problem, but i haven't find anything.
It sais "testAdd caused an ERROR: Missing argument". Simply the dataProvider isn't executed, when I run the test. I tried to put die() into the dataProvider and it hasn't died.
This is my code:
class LabelEntityModelTest extends PHPUnit_Extensions_Database_TestCase
{
private static $connection = NULL;
/**
* #var \CXNS\DB\Connections\Connection
*/
private static $appConnection;
private static $table;
public function __construct()
{
if (self::$connection) {
return;
}
$pdo = new \PDO($GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD']);
self::$appConnection = new \CXNS\DB\Connections\Connection(array("prefix" => "test_", "driver" => "pdo", "resource" => $pdo));
self::$appConnection->connect();
self::$connection = $this->createDefaultDBConnection($pdo, 'mysql');
self::$table = $this->createXMLDataSet(__DIR__ . '/fixtures/tables.xml');
}
protected function getDataSet()
{
return self::$table;
}
public function getConnection()
{
return self::$connection;
}
public function getAppConnection()
{
return self::$appConnection;
}
/**
* #group onlyThis
* #dataProvider providerAdd
*/
public function testAdd($labelId, $entityId)
{
$lem = new \appLibs\Labels\LabelEntityModel($this->getAppConnection(), "contacts");
$lem->add($labelId, $entityId);
$count = $this->getAppConnection()
->select("id")
->from("label_relationships")
->where("label_id = %i", $labelId)
->where("table_ref_id = %i", $entityId)
->count();
$this->assertEquals(1, $count, "insert failed");
}
public function providerAdd()
{
return array(
array(2, 3),
array(3, 4),
array(3, 4),
array(3, 4),
array(3, 4),
array(3, 4),
array(5, 7)
);
}
}
Thank you for your help.
You should never overwrite TestCase constructor.
PhpUnit has a specialized methods for initialization purposes called setUp and setUpBeforeClass, so I strongly suggest you to use that.
I´m pretty sure this is the cause of your problem.
Related
So I created a test service set :
class FMaiAffaireServiceTest extends TestCase
{
/**
* #var MyService
*/
private $myService;
private $typeaffaireTable;
private $mockDriver;
private $mockConnection;
private $mockPlatform;
private $mockStatement;
private $adapter;
private $sql;
public function setUp()
{
$this->mockDriver = $this->getMock('Zend\Db\Adapter\Driver\DriverInterface');
$this->mockConnection = $this->getMock('Zend\Db\Adapter\Driver\ConnectionInterface');
$this->mockDriver->expects($this->any())->method('checkEnvironment')->will($this->returnValue(true));
$this->mockDriver->expects($this->any())->method('getConnection')->will($this->returnValue($this->mockConnection));
$this->mockPlatform = $this->getMock('Zend\Db\Adapter\Platform\PlatformInterface');
$this->mockStatement = $this->getMock('Zend\Db\Adapter\Driver\StatementInterface');
$this->mockDriver->expects($this->any())->method('createStatement')->will($this->returnValue($this->mockStatement));
$this->adapter = new Adapter($this->mockDriver, $this->mockPlatform);
$this->sql = new Sql($this->adapter);
$mockTableGateway = $this->getMock('Zend\Db\TableGateway\TableGateway', array(), array(), '', false);
$maiAffaireTable = $this->getMockBuilder('Maintenance\Model\BDD\FMaiAffaireTable')
->setMethods(array())
->setConstructorArgs(array($mockTableGateway, $this->adapter, $this->sql))
->getMock();
$stub = $this->returnValue(new ResultSet());
$maiAffaireTable->expects($this->any())->method('listAffaires')->will($stub);
$this->myService = new FMaiAffaireService(
$maiAffaireTable
);
}
public function testListAffaires()
{
$this->myService->listAffaires(1,10);
}
}
My service looks like this, it is a call to my Zend Db function :
class FMaiAffaireService
{
private $maiAffaireTable;
public function __construct(
$maiAffaireTable,
) {
$this->maiAffaireTable = $maiAffaireTable;
}
public function listAffaires($iOffset, $iLimit) {
$aResults = $this->maiAffaireTable->listAffaires($iOffset, $iLimit);
return $aResults->toArray();
}
}
And here is the sample of my Zend DB function :
class FMaiAffaireTable
{
protected $tableGateway;
protected $adapter;
protected $sql;
public function __construct(
TableGateway $tableGateway,
Adapter $adapter,
Sql $sql
) {
$this->tableGateway = $tableGateway;
$this->adapter = $adapter;
$this->sql = $sql;
}
public function listAffaires($iOffset, $iLimit)
{
try {
$resultSet = $this->tableGateway->select(
function (Select $select) use (
$iOffset,
$iLimit
) {
$select->offset($iOffset);
$select->limit($iLimit);
}
);
return $resultSet;
} catch (\Exception $e) {
throw new \Exception($e);
}
}
}
And there is a big problem at the execution of PHPUnit :
1) Directories\FMaiAffaireServiceTest::testListAffaires reset() expects parameter 1 to be array, null given
I don't call reset() ANYWHERE ! That's the problem ... I think it's a PDO function but ... I'm a bit lost.
Thanks.
The problem is here
$stub = $this->returnValue(new ResultSet());
$maiAffaireTable->expects($this->any())->method('listAffaires')->will($stub);
A non-initialized ResultSet will not have a datasource, running toArray() on it (as you do in your service) will first try and reset the datasource, which will be null.
Try
$resultSet = new ResultSet();
$resultSet->initialize(array());
$stub = $this->returnValue($resultSet);
Is there anyway I can call a method within the dataprovider method? I tried doing it but the value passed from the dataProvider to the testAdd() method won't just pass. How do I do this?
PS: I do not want to call this from setUp() or setUpBeforeClass(), any way out?
<?php
class DataTest extends PHPUnit_Framework_TestCase
{
/**
* #dataProvider additionProvider
*/
public function testAdd($a, $b, $expected, $someValue)
{
echo $someValue;
$this->assertEquals($expected, $a + $b);
}
public function additionProvider()
{
$someValue = $this->doSomething();
return array(
array(0, 0, 0, $someValue),
array(0, 1, 1, $someValue),
array(1, 0, 1, $someValue),
array(1, 1, 3, $someValue)
);
}
protected function doSomething(){
return 5 * 6;
}
}
?>
Thanks
Let me first explain my problem.
I have a simple value object Poi. Private properties and getters/setters are left out for sake of simplicity in this example.
class Poi implements JsonSerializable
{
public $latitude;
public $longitude;
public $category;
public function __construct($category, $lat, $long)
{
$this->category = $category;
$this->latitude = $lat;
$this->longitude = $long;
}
public function jsonSerialize()
{
return array(
'lat' => $this->latitude,
'lng' => $this->longitude,
);
}
}
Some dataproviders are responsible for returning a array of Poi's. i.e.
class PoiProvider1
{
public function getPois()
{
return array(
new Poi('airport', 10, 10),
new Poi('airport', 10, 15),
new Poi('restaurant', 30, 30),
)
}
}
class PoiProvider2
{
public function getPois()
{
return array(
new Poi('hotel', 20, 20),
new Poi('airport', 30, 30),
)
}
}
Now I want an array structured a follows, which I can json_encode()
array(
'airport' => array(
new Poi('airport', 10, 10),
new Poi('airport', 10, 15),
new Poi('airport', 30, 30),
),
'restaurant' => array(
new Poi('restaurant', 30, 30),
),
'hotel' => array(
new Poi('hotel', 20, 20),
)
);
Which after a json_encode will end up in the following structure:
{
"airport":[
{"lat":10,"lng":10},
{"lat":10,"lng":15},
{"lat":30,"lng":30}
],
"restaurant":[
{"lat":30,"lng":30}
],
"hotel":[
{"lat":20,"lng":20}
]
}
I can create such a structure using array_merge and some array copying, like this:
$provider1 = new PoiProvider1();
$provider2 = new PoiProvider2();
$pois = array_merge($provider1->getPois(), $provider2->getPois());
$poisNew = array();
foreach ($pois as $poi)
{
$poisNew[$poi->category][] = $poi;
}
Obviously this is memory consuming and slow when dealing with lots of poi's.
There must be some nicer and faster way (i.e. using Iterators), but I'm not sure how to approach this. Could anyone give me some pointers how to proceed?
For speeding things up eliminate post processing.
ELIMINATION OF POST PROCESSING:
You can use another global or class static container for pois which auto indexes and stores them during construction like this:
class Poi implements JsonSerializable {
public static $json; // this is our new hero.
public $latitude;
public $longitude;
public $category;
public function __construct($category, $lat, $long){
$this->category = $category;
$this->latitude = $lat;
$this->longitude = $long;
array_push(self::$json[$category], $this); // this does the trick...
}
public function jsonSerialize()
{
return array(
'lat' => $this->latitude,
'lng' => $this->longitude,
);
}
}
Poi::$json = array();
Now at each poi creation, the poi instances are stored into Poi::$json exactly in the form you need.
GENERATING POI'S:
If you do not need to process poi's, this will simplify your providers also:
class PoiProvider1 {
public function getPois(){ // no need to return if they are just for json.
new Poi('airport', 10, 10); // because each instance will be autoMagically
new Poi('airport', 10, 15); // added to Poi::$json
new Poi('restaurant', 30, 30);
}
}
But if you do something else on poi instances do not use the code above...
ENCODING:
Since $json is an associated array you can get the required output effect by using
json_encode((object)Poi::$json);
The drawback is poi's will stick in memory and survive gc because they are reachable via Poi::$json. So after you json_encode set
Poi::$json = null;
I hope this helps.
I am trying to make an intermediate class which will log the queries in an array along with their execution time. Everything is fine and it works perfectly. But autocomplete doesnt work when i try to access the intermediate class. How can get the autocomplete to work. I am using Netbeans.
Intermediate classname is Model.
From my application, i have a class by the name Users which extends Model.
class Users extends Model
{
function __construct() {
parent::__construct();
$stmt = $this->prepare('SELECT * FROM users WHERE id=? ');
$stmt->bindValue(1, 1); //$stmt-> auto-complete is unavailable
$stmt->execute();
$rows = $stmt->fetchAll(PDO::FETCH_ASSOC);
print_r($rows); //i get results
}
}
My Model class looks like this.
class Model extends PDO
{
public static $log = array();
private $query_cache = array();
public function __construct() {
parent::__construct(
"mysql:dbname=".MYSQL_DB.";host=".MYSQL_HOST,
MYSQL_USER, MYSQL_PASSWORD
);
}
public function query($query) {
$time = "";
$query = mysql_real_escape_string(preg_replace( '/\s+/', ' ', $query ));
if (key_exists($query,$this->query_cache)
&& is_object($this->query_cache[$query]))
{
$result = $this->query_cache[$query];
} else {
$start = microtime(true);
$result = parent::query($query);
$time = microtime(true) - $start;
$this->query_cache[$query] = $result;
Logger::$logText['DATABASE'][] = array(
'QUERY' => $query,
'TIME' => number_format($time,4)
);
}
return $result;
}
/**
* #return LoggedPDOStatement
*/
public function prepare($query) {
return new LoggedPDOStatement(parent::prepare($query));
}
}
My LoggedPDOStatement looks like this.
class LoggedPDOStatement
{
/**
* The PDOStatement we decorate
*/
private $statement;
public function __construct(PDOStatement $statement) {
$this->statement = $statement;
}
/**
* When execute is called record the time it takes and
* then log the query
* #return PDO result set
*/
public function execute() {
$start = microtime(true);
$result = $this->statement->execute();
$time = microtime(true) - $start;
Model::$log[] = array(
'query' => '[PS] ' . $this->statement->queryString,
'time' => round($time * 1000, 3)
);
return $result;
}
/**
* Other than execute pass all other calls to the PDOStatement object
* #param string $function_name
* #param array $parameters arguments
*/
public function __call($function_name, $parameters) {
return call_user_func_array(
array($this->statement, $function_name), $parameters
);
}
}
Is their any better way of doing this ?
I have fixed this taking suggestions from #cillosis and #Touki
#Touki, i agree i shouldnt extend the PDO Class.
#cillosis, thanks for your comments.
This is the way i have written my class. I have not pasted the full code as its not complete yet. But i have checked it works. And i can log my queries as well. However i am not sure if i will be able to log the execution time.
class Model
{
/**
* The singleton instance
*
*/
static private $PDOInstance;
public function __construct($dsn="", $username = false, $password = false, $driver_options = false) {
if (!self::$PDOInstance) {
try {
self::$PDOInstance = new PDO(
"mysql:dbname=".MYSQL_DB.";host=".MYSQL_HOST,
MYSQL_USER, MYSQL_PASSWORD
);
} catch (PDOException $e) {
die("PDO CONNECTION ERROR: " . $e->getMessage() . "<br/>");
}
}
return self::$PDOInstance;
}
/**
* Initiates a transaction
*
* #return bool
*/
public function beginTransaction() {
return self::$PDOInstance->beginTransaction();
}
public function prepare($statement, $driver_options = false) {
//log the $statement
if (!$driver_options)
$driver_options = array();
return self::$PDOInstance->prepare($statement, $driver_options);
}
}
abstract class App_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase {
protected $App;
/**
* #return PHPUnit_Extensions_Database_DB_IDatabaseConnection
*/
public function log($text)
{
$file = '/Applications/MAMP/htdocs/zumba/app/vendors/billing/tests/abstract/log.txt';
$current = file_get_contents($file);
$current .= $text."\n";
file_put_contents($file, $current);
}
final public function getConnection()
{
$this->log("Initiate Get Connection");
$this->App = new App();
if ($this->conn === null) {
if (self::$pdo == null) {
self::$pdo = new PDO( $GLOBALS['DB_DSN'], $GLOBALS['DB_USER'], $GLOBALS['DB_PASSWD'] );
}
$this->conn = $this->createDefaultDBConnection(self::$pdo, $GLOBALS['DB_DBNAME']);
}
return $this->conn;
}
protected function getDataSet()
{
$this->log("Initiate GetDataSet");
return new ZumbaDbUnitArrayDataSet(array(
'guestbook' => array(
array('id' => 1, 'content' => 'Hello buddy!', 'user' => 'joe', 'created' => '2010-04-24 17:15:23'),
array('id' => 2, 'content' => 'I like it!', 'user' => null, 'created' => '2010-04-26 12:14:20'),
),
));
}
protected function setUp() {
$this->log("Initiate Setup");
$this->App = new App();
}
protected function tearDown() {
$this->log("Initiate Tear Down");
unset($this->App);
}
}
I added a log to keep track of progress but same outcome
Below is Output
Configuration read from
F Initiate Setup Initiate Tear Down
Time: 0 seconds, Memory: 6.25Mb
There was 1 failure:
1) BillingControlTest::test_funrun
Failed asserting that false is true.
FAILURES!
Tests: 1, Assertions: 1, Failures: 1.
I execute this file
class BillingControlTest extends App_Tests_DatabaseTestCase {
function test_funrun()
{
$returnVal = $this->App->query("UPDATE guestbook SET created = NOW() WHERE id = 1");
$this->assertTrue($returnVal);
}
}
As you can see. it runs through the setup and tearDown but skips getConnection and getDataset. I am following the tutorial on the website.