Mockery does not mock propeties of class - php

i have test:
class ContacsBLOTest extends TestCase
{
public function testsearch()
{
$Ctrl= new ContactsBLO;
$data=['id'=>1,'name'=>'The Manh','phone'=>'123456566','address'=>'180 cao lo','note'=>''];
$data=[(object)$data];
$mock_data=\Mockery::mock('DB');
$mock_data->shouldReceive('all')->andReturn($data);
$mock_ctrl= new ContactsBLO;
$mock_ctrl->select=$mock_data;
$result=$mock_ctrl->search('manh');
$this->assertNotNull($result);
}
and this is ContacsBLO class:
class ContactsBLO
{
public $db,$not_allow,$Validation;
public function __construct(){
$this->db=new DB;
$this->not_allow=['"','\'','%'];
$this->Validation = new ContactValidation;
}
public function search($request=null){
$length=strlen($request);
for ($i=0;$i<$length;$i++) {
$forbidden=$this->not_allow;
if(in_array($request[$i],$forbidden)){
return (['messenger'=>'We are not allow special character in your request','old_input'=>$request]);
}
else{
return $data=$this->db->select('*',$request);
}
}
}
}
DB::class(i define connect to data base and define select method:
class DB
{
public $obj = null;
public $table = 'contacts';
public function __construct(){
$dsn="mysql:host=".HOST."; dbname=".DB_NAME;
$this->obj = new \PDO($dsn, DB_USER, DB_PASS);
$this->obj->query("set names 'utf8' ");
}
public function select($row=null,$query=null) {
$sql='SELECT '.$row.' FROM '.$this->table.' '.$query;
$data = $this->obj->prepare($sql);
$data->execute();
return $data->fetchAll(\PDO::FETCH_CLASS);
}
}
But when i run xdebug and run this test, $forbidden is null,it mean mock method return real data, not mock data. i dont know why.
Anyone can help me! Please!

You never inserted your mock into your class, besides when using the new keyword to create a class instance it's difficult to mock. Your only chance in such cases is to use class alias.
To avoid all this you can pass in the database instance through the ContactsBLO constructor.
class ContacsBLOTest extends TestCase
{
public function testSearch()
{
$data = ['id'=>1,'name'=>'The Manh','phone'=>'123456566','address'=>'180 cao lo','note'=>''];
$data = json_decode(json_encode($data));
$mock_contact = \Mockery::mock(DB::class);
$mock_contact->shouldReceive('select')->andReturn($data);
$Ctrl = new ContactsBLO($mockDB);
$result = $Ctrl->search('manh');
$this->assertNotNull($result);
}
}
class ContactsBLO
{
public $db;
public $not_allow;
public $Validation;
public function __construct(DB $db) {
$this->db = $db;
$this->not_allow = ['"','\'','%'];
$this->Validation = new ContactValidation;
}
public function search($request=null){
$length=strlen($request);
for ($i=0;$i<$length;$i++) {
$forbidden = $this->not_allow;
if(in_array($request[$i],$forbidden)){
return (['messenger'=>'We are not allow special character in your request','old_input'=>$request]);
}
else{
return $data = $this->db->select('*',$request);
}
}
}
}
I tested it with this code and it worked fine. Please check if the DB class is imported at the top of your test file. You also have to append Test to all test file names and classes (see above).

I was change it to:
$mock_data=\Mockery::mock('DB');
$mock_data->shouldReceive('select')->andReturn($data);
$mock_ctrl= new ContactsBLO;
$mock_ctrl->db=$mock_data;
$result=$mock_ctrl->search();
And it is working for me, thank for all help

Related

oop structure for make class such as PDO class structure

How to make class structure like PDO or ORM
$query = DB::table('users')->select('name');
$users = $query->addSelect('age')->get();
OR
$stmt = $pdo->prepare($sql);
$stmt->bindvalue(':u',intval($_SESSION['userId']),PDO::PARAM_INT);
$stmt->execute();
What is returned in to $query or $stmt?
how to design class structure like them?
Thank you
EDIT
$query = DB::table('users')->select('name');
meaning :
function select(){
//
return $this;
}
what's returned in to $query for this structure :
$query->addSelect('age')->get();
PDO is done by returning a new class (PDOStatement) with its own methods (read more about it), but it would be the same as:
<?php
class ClassOne
{
private $connection;
public function __construct($database_stuff)
{
$this->connection = $database_stuff;
}
public function prepare($sql)
{
// Code that does something with the $sql
// Then return a new class
return new ClassTwo($this);
}
}
class ClassTwo
{
private $ClassOne;
public function __construct(ClassOne $Class)
{
$this->ClassOne = $Class;
}
public function execute()
{
// Code that does something with ClassOne
}
}
# Start that initial class
$Class = new ClassOne('database:type;host=example;etc=yadayada');
# Do class one method
$query = $Class->prepare("SELECT * FROM fake_table");
# $query is now ClassTwo, so you do method from ClassTwo
$query->execute();
The ability to chain methods together is achieved because the current method returns the object back in the form of $this:
<?php
class DBClass
{
protected $connection,
$value;
public function __construct($connection)
{
$this->connection = $connection;
}
public function prepare($value)
{
$this->value = $value;
# Return the object
return $this;
}
public function execute()
{
echo $this->value;
# Return the object
return $this;
}
}
$con = new DBClass("login creds");
$con->prepare("update stuff if stuff = 'things'")->execute();
?>

PHP Design Pattern for using instantiated classes

We are trying to understand the best way to use mysqli/other classes in multiple custom classes so that we don't instantiate a new object every time.
Is the code below the best/correct way of doing this?
The functions are only examples.
Thank you :)
<?php
class Base {
public function __get($name) {
if($name == 'db'){
$db = new mysqli('**', '*s', '*', '*');
$this->db = $db;
return $db;
}
if($name == 'blowfish'){
$blowfish = new PasswordHash(8, true);
$this->blowfish = $blowfish;
return $blowfish;
}
}
}
class A extends Base {
public function validate($username, $password) {
$query = $this->db->query("SELECT * FROM users");
return $query->num_rows;
}
public function password($password)
{
return $this->blowfish->HashPassword($password);
}
}
class PasswordHash {
public function __construct($iteration_count_log2, $portable_hashes) { }
public function HashPassword($password) {
return $password;
}
}
$a = new A;
echo $a->validate('test','test'); // returns number rows count as expected
echo $a->password('password123'); // returns password123 as expected
?>
You are/should probably be more interested in Dependency Injection instead of creating a tight coupling of Base|A and the MySQL database.

PHP : Function argument must be an Object with dynamic class name

so I am new in the world of object oriented programming and I am currently facing this problem (everything is described in the code):
<?php
class MyClass {
// Nothing important here
}
class MyAnotherClass {
protected $className;
public function __construct($className){
$this->className = $className;
}
public function problematicFunction({$this->className} $object){
// So, here I obligatorily want an $object of
// dynamic type/class "$this->className"
// but it don't works like this...
}
}
$object = new MyClass;
$another_object = new MyAnotherClass('MyClass');
$another_object->problematicFunction($object);
?>
Can anyone help me ?
Thanks, Maxime (from France : sorry for my english)
What you need is
public function problematicFunction($object) {
if ($object instanceof $this->className) {
// Do your stuff
} else {
throw new InvalidArgumentException("YOur error Message");
}
}
Try like this
class MyClass {
// Nothing important here
public function test(){
echo 'Test MyClass';
}
}
class MyAnotherClass {
protected $className;
public function __construct($className){
$this->className = $className;
}
public function problematicFunction($object){
if($object instanceof $this->className)
{
$object->test();
}
}
}
$object = new MyClass;
$another_object = new MyAnotherClass('MyClass');
$another_object->problematicFunction($object);
That's called type hinting and what you want to do is just not supported.
If all those dynamic class names have something in common (e.g., they're different implementations for certain feature) you probably want to define a base (maybe abstract) class or an interface and use that common ancestor as type hint:
<?php
interface iDatabase{
public function __contruct($url, $username, $password);
public function execute($sql, $params);
public function close();
}
class MyClass implements iDatabase{
public function __contruct($url, $username, $password){
}
public function execute($sql, $params){
}
public function close(){
}
}
class MyAnotherClass {
protected $className;
public function __construct($className){
$this->className = $className;
}
public function problematicFunction(iDatabase $object){
}
}
Otherwise, just move the check to within problematicFunction() body, as other answers explain.

Using SQL function from SQL handling class in other functions

I have created an SQL function SQLquery in a class called SQLHandling
It looks like this:
/***********************************************************
* SQLquery takes a full SQL query and runs it
* If it fails it will return an error otherwise it will return
* the SQL query as given.
************************************************************/
function SQLquery($query) {
$q = mysql_query($query);
if(!$q) {
die(mysql_error());
return false;
} else {
return $q;
}
}
Is there anyway I can use this function in other classes functions without adding
$db = new SQLHandling();
$db->SQLquery($sql);
In every function where I will use it.
I know I can run SQLHandling::SQLquery($sql); but I am trying to avoid that.
use inheritance
refer:
http://php.net/manual/en/language.oop5.inheritance.php
but still you will need to use parent::fun() or $this->fun()
or put it as a public function then use any where.
example:
<?php
function c()
{
echo "moi";
}
class b extends a
{
public function d(){
parent::c();//Hai
$this->c();//Hai
c();//moi
}
}
class a{
public function c(){
echo "Hai";
}
}
$kk = new b();
$kk -> d();
?>
You could instantiate SQLHandling on class level, like so:
private $db;
public function __construct()
{
$this->db = new SQLHandling();
}
public function x()
{
$this->db->query('X');
}

PHPUnit Database Testing Exception

I'm trying to get started with setting up unit tests using a MySQL database and I'm running into this exception:
DBTest::test__getException()
Argument 1 passed to PHPUnit_Extensions_Database_DataSet_DefaultTableIterator::__construct() must be an array, null given.
I don't know what I could be missing
My Unit Test Code:
<?php
class DBTest extends Generic_Tests_DatabaseTestCase {
//...
public function getDataSet() {
$dataSet = $this->createMySQLXMLDataSet(dirname(__FILE__)."/../db/t_enroll_fixtures.xml");
return $dataSet;
}
public function setUp() {
$this->X = $this->getMock('\X\Engine\X');
$this->model = new Model($this->X, 't_users');
$this->className = get_class($this->model);
parent::setUp();
}
public function tearDown() {
$this->X = NULL;
$this->model = NULL;
parent::tearDown();
}
public function testMagicFields() {
$this->getConnection()->addTable('t_enroll');
$this->assertEquals(10, $this->getConnection()->getRowCount('t_enroll'));
}
}
?>
The Generic_Test_DatabaseTestCase Class:
<?php
require_once "PHPUnit/Extensions/Database/TestCase.php";
abstract class Generic_Tests_DatabaseTestCase extends PHPUnit_Extensions_Database_TestCase {
// only instantiate pdo once for test clean-up/fixture load
static private $pdo = null;
// only instantiate PHPUnit_Extensions_Database_DB_IDatabaseConnection once per test
private $conn = null;
final public function getConnection() {
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;
}
}
?>
What am I missing?
I had the same problem. The reason was, that the XML fixture was generated by MySQLDump and someone removed the <database name="xyz"> node.
This turned $this->tables in PHPUnit into NULL instead Array
This happened to me after I added a schema location for the mysqldump like
<mysqldump xmlns="mysqldump"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="mysqldump mysqldump.xsd ">
After I removed the namespace, it worked:
<mysqldump xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">

Categories