Codeception multiple tests, 1 script - php

I think I might be getting the concept wrong or not thinking about something correctly. I'm looking for a way to connect to db, and then run a selenium test (in phantomjs) for every row of a table. The test is to check for broken images on a bespoke CMS, and could be applied to any CMS.
I basically want to run an acceptance test for every page (of a specific type) by loading their IDs from the db and then running a separate test for each ID.
This is what I have so far:
$I = new WebGuy($scenario);
$results = $I->getArrayFromDB('talkthrough', '`key`', array());
foreach ($results as $r) {
$I->wantTo('Check helpfile '.$r['key'].'for broken images');
$I->amOnPage('/talkThrough.php?id='.$r['key']);
$I->seeAllImages();
}
This works to some extent in that it executes until the first failure (because it is running as 1 test with many assertions).
How do I make this run as individual tests?

I ended up looping through and storing the key that failed in a comma delimited string and setting a bool to say failures found.
$I = new WebGuy($scenario);
$results = $I->getArrayFromDB('talkthrough', '`key`', array());
$failures = "Broken help files are: ";
$failures_found = false;
foreach ($results as $key => $r) {
$I->wantTo('Check helpfile '.$r['key'].'for broken images');
$I->amOnPage('/talkThrough.php?id='.$r['key']);
$allImagesFine = $I->checkAllImages();
if($allImagesFine != '1')
{
$fail = $r['key'].",";
$failures.= $fail;
$failures_found = true;
}
}
$I->seeBrokenImages($failures_found,$failures);
With following as my webhelper
<?php
namespace Codeception\Module;
// here you can define custom functions for WebGuy
class WebHelper extends \Codeception\Module
{
function checkAllImages()
{
$result = $this->getModule('Selenium2')->session->evaluateScript("return (function(){ return Array.prototype.slice.call(document.images).every(function (img) {return img.complete && img.naturalWidth > 0;}); })()");
return $result;
}
function getArrayFromDB($table, $column, $criteria = array())
{
$dbh = $this->getModule('Db');
$query = $dbh->driver->select($column, $table, $criteria);
$dbh->debugSection('Query', $query, json_encode($criteria));
$sth = $dbh->driver->getDbh()->prepare($query);
if (!$sth) \PHPUnit_Framework_Assert::fail("Query '$query' can't be executed.");
$sth->execute(array_values($criteria));
return $sth->fetchAll();
}
function seeBrokenImages($bool,$failArray)
{
$this->assertFalse($bool,$failArray);
}
}
Thanks for the submitted answers

That's not going to work. Please avoid loops and conditionals in your tests.
You should place the key manually. And not get them from database. As it introduces additional complexity.

It might not be the best design choice, but If you really want to follow this approach you could use the specify tool from codeception, in order to allow your test continue running even if one assertion fails:
https://github.com/Codeception/Specify

Related

PHP Loop through dynamic array

I have a webapplication with a php backend.
At a certain interval checks need to be run on all users. Running these checks takes some time, more importantly: they should not be executed on non-existing users. The users are received from a database and can change mid-way through running the checks. My current solution is:
<?php
require_once 'databaseUtils.php';
$users = getUsersFromDatabase();
//Sample:
while(true) {
foreach(GetUsers() as &$user) {
//I'd rather not:
if(checkIfUserIsInDatabase($user) {
var_dump($user);
sleep(1); //Checking takes time...
}
}
echo "Going again in 5s!";
sleep(5); //Interval
}
function GetUsers() {
return $users;
}
//Called from outside
function removeUser($user) {
global $users;
removeUserFromDatabase($user);
if(($key = array_search($user, $users)) !== false) {
unset($users[$key]);
}
}
?>
But I'm still looping needlessly through the user that isn't realy in the GetUsers() anymore. Is there a way to loop through all values of an array in which elements can get deleted from outside?
If you want to check each user if he is still in the database, you will need to query his information from database, so it will take more efforts than checking each item in array (if it is not more resource spending).
But I will suggest to get users in smaller portions instead of all users. And check portion by portion.
Firstly, you might need to consider to rework your entire business logic.
Do not use endless loops (while(true)) and global variables (global $users).
To loop through all users you can use generator concept and retrieve existent users one by one. So you will get only the next user from the database during each iteration:
function getUsersFromDatabase($db)
{
$id = 0;
while (($user = $db->query("SELECT * FROM `users` WHERE `id` > $id LIMIT 1"))) {
yield $user;
$id = $user->id;
}
}
foreach (getUsersFromDatabase($db) as $user) {
checkUser($user);
}
I do not know your framework or DB adapter details, so the code snippet is generic and should be considered as pseudo code.

Codeigniter Database Record retrival - Best Practise - Performance

I'm checking an PHP project which is build using PHP Codeigniter. I'm new to PHP, I like to get your valuable feedback
To retrieve name and item number in php library/controller, call is made to Item Model as below
'name'=>$this->CI->Item->get_info($item_id)->name
'item_number'=>$this->CI->Item->get_info($item_id)->item_number
I suspect above two line of code will make two independent database sql call instead of one call to retrive the two column of same table. Ie., there will be performance degrade. But somebody can please let me know whether it fires two sql statements please?
I think we need to handle like object
$row = $this->CI->Item->get_info($item_id);
echo $row->name;
echo $row->item_number;
Please suggest. Thanks in advance.
Model Function:
function get_info($item_id)
{
$this->db->from('items');
$this->db->where('item_id',$item_id);
$query = $this->db->get();
if($query->num_rows()==1)
{
return $query->row();
}
else
{
//Get empty base parent object, as $item_id is NOT an item
$item_obj=new stdClass();
//Get all the fields from items table
$fields = $this->db->list_fields('items');
foreach ($fields as $field)
{
$item_obj->$field='';
}
return $item_obj;
}
}

Having troubles with mysqli::fetch_object();

after reading like 5 hours on Google I can't fix something with MySQLI.
I spent all my life programming in MySQL, and now I am trying to update my knowledge using mysqli but I have some troubles.
I have a little function called news_Default() like this:
<?php
Class Test extends DB{
public function news_Default(){
$query = $this->db->query('SELECT * FROM news');
if($query->num_rows == 0)
return false;
else
return $query->fetch_object();
}
}
?>
And I used in this way:
<?php
while($new = $panel->news_Default()){
print_r($new);
}
?>
In MySQL, when I return the object, I can use it with 'while' or 'foreach' loop without problems, but the real problem is here, with mysqli.
When I used the 'while' (second codeblock), it loops 6,000 times (I used a $counter++ to test it), and when I used foreach, it loops exactly 7 times. In my table called 'news' I have only two records. So, how can I return the object and use it outside without having this problems? Because when I use it inside the class like $new = $query->fetch_object() works perfect.
You are doing sql query every time when you are calling news_Default.
Examle for fixing it.
Class Test extends DB{
private $_cached_news = null; // let's store our query result
public function news_Default(){
if ($this->_cached_news === null){ // not stored?
$this->_cached_news = $this->db->query('SELECT * FROM news');} // let's query
$return = $query->fetch_object(); // get next object
if (!$return) // there is no objects anymore?
$this->_cached_news = null; // let's clear our result
return $return;
}
}

Generic fast coded PHP MySQL dynamic insert/update query creating table/fields named as variables if doesnt exists

I'm looking for a way to make MySQL insert/update queries more dynamic and fast to code since sometimes one just need another field in a form (when for example prototyping an application). This might be a dumb question.
My idea is to make an insert or update if ids match, and if table/fields doesn't exists create it with one function dynamically.
<?php
// $l is set with some db-login stuff
// creates and inserts
$f[] = nf(1,'this_id_x'); // this_id_* could be a prefix for ids
$f[] = nf('value yep',$fieldname_is_this2)
$tbl_name = "it_didnt_exist";
nyakilian_fiq($l, $tbl_name, $f);
// Done!
//This would do an update on above
$fieldname_is_this2 = "this is now updated";
$f[] = nf(1,'this_id_x');
$f[] = nf($fieldname_is_this2); // the function takes the variable name as field name
$tbl_name = "it_didnt_exist";
nyakilian_fiq($l, $tbl_name, $f);
?>
I have been using this function with success. It doesn't add a column but that is against the structure of my MVC framework. Try something like this:
public function save(DatabaseConnection &$db)
{
$properties = get_object_vars($this);
$table = $this->getTableName();
// $cols = array();
// $values = array();
foreach ($properties as $key => $value) {
$cols[] = "`$key`";
$values[] = '"'.$value.'"';
if ($value != NULL) {
$updateCols[] = "`$key`".' = "'.$value.'"';
}
}
$sql = 'INSERT INTO '.$table.' ('.implode(", ", $cols).') VALUES ('.implode(", ", $values).') ON DUPLICATE KEY UPDATE '.implode(", ", $updateCols);
$stmnt = $db->prepare($sql);
var_dump($stmnt);
if ($stmnt->execute($values)) return true;
return false;
}
I have a model abstract class that I extend with a child class for each database table. This function sits in the model abstract. Each child class contains a public property [so I can use PDO::fetchObject()] that corresponds to a column name in the table. If I need to create the table on the fly, I add a function to the child class to do so.
This is quite unusable approach.
You are trying to mix into one single function (not even a class(!) a functionality that fits for a decent framework. That's just impossible (or unusable for some parts).
Yet it resembles major frameworks' Models in many aspects.
So, I could give just some recommendations
Do not create tables dynamically. Data structure is a backbone of the application and have to be solid.
do not take too much considerations (like "If an ID is passed"). it will tie your hands for whatever more complex case
take a look at some major frameworks - it seems your wishes are already fulfilled with their codegeneration feature (an ugliest thing that ever existed on the Erath in my private opinion). They're working pretty the same way you're talking about: you have to only define a Model and the rest is done by framework's methods

Is it possible to call a PHP function from an SQL query?

Say there is a special PHP function foo($number) that returns double the value of its input. Further, say there is a table that contains the column "number." Is there a way to have the PHP function and SQL query to run together so that I would get the following:
Number | Double
================
1 | 2
5 | 10
While in this simple example column Double can easily be implemented within the SQL statement, answers should cover the more general case of calling any PHP function, as there are many operations that are difficult to impossible in SQL but easy in PHP.
No, since the query results come straight from MySQL. You can apply the function to the result set after you execute your query, either by using a loop or by applying your function to the results using array_map() function.
Depending on what you're actually trying to achieve it might be possible to decouple the data source and the consumer a bit, enough to put another component between them.
Let's start with
<?php
$result = getData($pdo); // a)
doSomething($result); // b)
function getData($mysql) {
return mysql_query('SELECT x FROM soTest', $mysql);
}
function doSomething($result) {
while ( false!==($row=mysql_fetch_assoc($result)) ) {
echo ' ', join(', ', $row), "\n";
}
echo "----\n";
}
There's very little you can do to alter a mysql result resource. And doSomething() does nothing more than iterating over the result set. It does nothing that is special to a mysql result set, yet it allows nothing else but this exact resource type by using mysql_fetch_xyz().
Let's try this again using PDO (PDO_MYSQL).
$result = getData($pdo);
doSomething($result);
function getData($pdo) {
return $pdo->query('SELECT x FROM soTest');
}
function doSomething(PDOStatement $result) {
while ( $row=$result->fetch(PDO::FETCH_ASSOC) ) {
echo ' ', join(', ', $row), "\n";
}
echo "----\n";
}
That didn't change much. Some names but essentially this is the same. But PDOStatement implements the Traversable interface, so you can use it directly with foreach.
$result = getData($pdo);
doSomething($result);
function getData($pdo) {
return $pdo->query('SELECT x FROM soTest', PDO::FETCH_ASSOC);
}
function doSomething($traversable) {
foreach( $traversable as $row ) {
echo ' ', join(', ', $row), "\n";
}
echo "----\n";
}
That's a game changer... We can pass any traversable/iterator to doSomething() and it still does more or less the same thing as before.
Now we can put something "between" getData() and doSomething(). This something takes an inner iterator (like getData() provides in the form of an PDOStatement) and behaves itself like an iterator (so DoSomething() can use it) returning all elements of its inner iterator but modifying some elements.
I chose to extend FilterIterator for this example for no particular reason. You need php 5.3+ to run this demo since it uses an anonymous function:
<?php
$pdo = initDemo();
echo "#1: passing \$result\n";
$result = getData($pdo); // a)
doSomething($result); // b)
echo "#2: passing ModifyIterator\n";
$result = getData($pdo); // exact same as a)
$result = new ModifyIterator($result, null, function($e) {
$e['y'] = '/' . ($e['x'] * 2) .'/';
return $e;
});
doSomething($result); // exact same as b)
function getData($pdo) {
return $pdo->query('SELECT x FROM soTest', PDO::FETCH_ASSOC);
}
function doSomething($traversable) {
foreach($traversable as $row) {
echo ' ', join(', ', $row), "\n";
}
echo "----\n";
}
class ModifyIterator extends FilterIterator {
protected $fnAccept, $fnModify;
public function __construct($it, $fnAccept, $fnModify) {
// todo: test parameters!
$this->fnAccept = $fnAccept;
$this->fnModify = $fnModify;
if ( !($it instanceof Iterator) ) {
$it = new IteratorIterator($it);
}
parent::__construct($it);
}
public function accept() {
return $this->fnAccept ? $this->fnAccept(parent::current()) : true;
}
public function current() {
if ( $this->fnModify ) {
$fn = $this->fnModify;
return $fn(parent::current());
}
return parent::current();
}
}
function initDemo() {
$pdo = new PDO('mysql:host=localhost;dbname=test', 'localonly', 'localonly');
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$pdo->exec('CREATE TEMPORARY TABLE soTest (x int auto_increment, primary key(x))');
$pdo->exec('INSERT INTO soTest VALUES (),(),(),(),()');
return $pdo;
}
prints
#1: passing $result
1
2
3
4
5
----
#2: passing ModifyIterator
1, /2/
2, /4/
3, /6/
4, /8/
5, /10/
----
The important part is that ModifyIterator forces very little particular behaviour on the inner iterator (e.g. you can still use an unbuffered query without the need to transfer all the data into the php process' memory at once) and that both getData() and doSomething() are left unchanged.
One way would be to fetch the results into objects:
class NumberDoubler
{
public $number;
public function __construct()
{
$this->number *= 2;
}
}
$pdo = new PDO('mysql:host=localhost;dbname=db_name', 'uname', 'pword');
$stmnt = $pdo->query('SELECT number FROM db_table');
$result = $stmnt->fetchAll(PDO::FETCH_CLASS, 'NumberDoubler');
print_r($result);
The result will be an array of objects with '$number' doubled. Of course, iteration will still be done "behind the scenes", and the manual warns, "Using this method to fetch large result sets will result in a heavy demand on system and possibly network resources."
See also PDOStatement::setFetchMode().
You don't need to use PHP. You can just execute a regular SQL statement as follows.
SELECT number, number * 2 FROM tablename;
//Your query would prob be like so.
$query = mysql_query("SELECT (number * 2) as double,number FROM table");
echo '<table>';
while($row = mysql_fetch_assoc($query))
{
echo sprintf('<tr><td>%d</td><td>%d</td></tr>',$row['number'],$row['double']);
}
echo '</table>';
I think I understand your question.
It sounds as though you want to pull a number from a database and double it through a php function.
I would first learn to write the php function... Check this out for a tutorial.
Once you have that down, pull your number from the database. Here is a tutorial on how to do that.
This is all about learning. Me posting code for you to just copy doesn't help you learn and is basically a waste of my time. Best of luck.
It depends on what the function is doing. Basic stuff like arithmetic can be done with SQL directly. Otherwise, you can loop over the result array and run the function in the particular field, e.g.:
$rows = array();
foreach(($row = mysql_fetch_assoc($result))) {
$row['double'] = func($row['number']);
rows[] = $row;
}
No, it's impossible to use php function() and sql together
However, you can get results from SQL database and apply whatever PHP function on it

Categories