PHPUnit: Calling methods inside dataprovider - php

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

Related

PHP class that sorts an ordered integer array with the help of sort() function

I have written down the following for the above question
<?php
class sortClass{
public function __construct(array $arrayPassed){
return sort($arrayPassed);
}
}
$newarray=array(11,-2,4,35,0,8,-9);
$sorted = new sortClass($newarray);
print_r($sorted);
?>
And the output is 'sortClass Object()' , I'd like some help to understand why it would not print out the sorted array , When we instantiate a class - the constructor will automatically execute and return what ever it returns right? so why isn;t printing $sorted object printing whats returned in the constructor?
You don't need a wrapper class just to sort, you can just run sort function directly, the issue with your code is, returning in __constructor.
I suggest you run it directly like this:
<?php
$newarray = array(11,-2,4,35,0,8,-9);
sort($newarray);
print_r($newarray);
?>
or this one if you still need a OOP version:
<?php
class sortClass{
private $arrayPassed = [];
public function __construct(array $arrayPassed){
$this->arrayPassed = $arrayPassed;
}
public function sort() {
sort($this->arrayPassed);
return $this->arrayPassed;
}
}
$newarray = array(11,-2,4,35,0,8,-9);
$sortClass = new sortClass($newarray);
print_r($sortClass->sort());
https://www.php.net/manual/en/language.oop5.basic.php
You misunderstood OOP, you need to learn about it before write code.
I give a workaround just for the idea:
class sortClass
{
public $sorted;
public function __construct(array $arrayPassed)
{
sort($arrayPassed);
$this->sorted = $arrayPassed;
}
}
$newarray = array(11, -2, 4, 35, 0, 8, -9);
$sorted = new sortClass($newarray);
var_dump($sorted->sorted);
You can't return anything from a constructor method. You have to create a new public method which return the sorted the value.
class MyClass
{
private $sorted;
public function __construct(array $input)
{
$this->sorted = asort($input);
}
public function sortedArray()
{
return $this->sorted;
}
}
$arr = [11, -2, 4, 35, 0, 8, -9];
$sorted = new MyClass($arr);
print_r($sorted->sortedArray());
AS Nigel Ren explain you can't return from a constructor method. You need a new method to return the sorted the value. Check my code
class sortClass{
private $sortedArray;
public function __construct(array $arrayPassed){
$this->sortedArray = asort($arrayPassed);
}
public function getSortedArray(){
return $this->sortedArray;
}
}
$newarray=array(11,-2,4,35,0,8,-9);
$sorted = new sortClass($newarray);
print_r($sorted->getSortedArray());

PHP - Service layer class instantiation causing infinite loop

I have service layer classes which performs the business logic.
I have a class say UserService which performs user role related service like checking if user is admin, user has access to project, user has particular role or not, etc. And there is a another class say ProjectService which deals with project related things like getting project members, project details, etc.
UserService
$projectService; //class variable
hasProjectAccess(){
{
...
projectMember = projectService->getProjectMembers();
...
}
isUserAdmin(){
return true|false; //just an example
}
ProjectService
$userService; //class variable
getProjectMembers(){
{
...
perform some logic to create array of members
...
if(userService.isUserAdmin())
.. perform some other logic
...
}
I am using Slim 3, where I use it's Container class to instantiate and inject all dependencies.
Now when I try to instantiate UserService class I have to instantiate the ProjectService class inside it (using setters method), which in turn has to instantiate UserService class .... and so on... which creates an infinite loop (cyclic dependency).
I am trying to achieve something like in Java/Spring, where you have different services which you need in your class and they wired into it using Spring so you do not have to worry about the cyclic dependency.
I am not much familiar with PHP except the basics.
Let me know if more information is needed.
Pimple which is used as dependency container in Slim3, isn't that strong as Spring in Java f.ex. it is only a simple container, which just has the basic functionallity.
So when just using the pimple functions you need to initialize your objects which have a cyclic dependency by yourself:
class A {
private $b;
public function __construct(B $b) { $this->b = $b; }
}
class B {
private $a;
public function setA(A $a) { $this->a = $a; }
}
$container = new \Slim\Container;
$b = new B;
$a = new A($b);
$b->setA($a);
$container['A'] = function($c) use ($a) {
return $a;
};
$container['B'] = function($c) use ($b) {
return $b;
};
$aFromContainer = $container['A'];
I've made some small changes to the slim container that it will be possible to automate this process (althrough this work, I dont know how well it does in larger projects).
class MyContainer extends \Slim\Container
implements \Interop\Container\ContainerInterface {
private $resolveStack = [];
private $resolveLater = [];
/**
* #see \Pimple\Container::offsetSet()
*
* Additionally define objects which will be later set with a method.
*/
public function resolveLater(string $id, callable $value, array $later) {
$this[$id] = $value;
foreach($later as $item) {
if(!isset($this->resolveLater[$item])) $this->resolveLater[$item] = [];
$this->resolveLater[$item][] = $id;
}
}
/**
* #see \Pimple\Container::offsetGet()
*
* Additionally set objects which were previously defined in #resolveLater.
*/
public function offsetGet($id) {
if(isset($this->resolveStack[$id])) { return $this->resolveStack[$id]; }
$this->resolveStack[$id] = parent::offsetGet($id);
if(isset($this->resolveLater[$id])) {
foreach($this->resolveLater[$id] as $item) {
$this[$item]->{'set' . $id}($this->resolveStack[$id]);
}
}
return array_pop($this->resolveStack);
}
}
Example for the above:
class A {
public function setB(B $b) { $this->b = $b; }
public function setC(C $c) { $this->c = $c; }
}
class B {
public function setA(A $a) { $this->a = $a; }
public function setC(C $c) { $this->c = $c; }
}
class C {
public function setA(A $a) { $this->a = $a; }
public function setB(B $b) { $this->b = $b; }
}
$container = new MyContainer;
$container->resolveLater('A', function($container) {
return new A;
}, ['B', 'C']);
$container->resolveLater('B', function($container) {
return new B;
}, ['A', 'C']);
$container->resolveLater('C', function($container) {
return new C;
}, ['A','B']);
$a = $container['C'];
var_dump($a);
This would output something like this:
object(C)[20]
public 'b' =>
object(B)[22]
public 'a' =>
object(A)[21]
public 'b' =>
&object(B)[22]
public 'c' =>
&object(C)[20]
public 'c' =>
&object(C)[20]
public 'a' =>
object(A)[21]
public 'b' =>
object(B)[22]
public 'a' =>
&object(A)[21]
public 'c' =>
&object(C)[20]
public 'c' =>
&object(C)[20]

configure own iterator for class php?

I have a class Foo, I need to do :
$foo = new Foo();
foreach($foo as $value)
{
echo $value;
}
and define my own method to iterate with this object, exemple :
class Foo
{
private $bar = [1, 2, 3];
private $baz = [4, 5, 6];
function create_iterator()
{
//callback to the first creation of iterator for this object
$this->do_something_one_time();
}
function iterate()
{
//callback for each iteration in foreach
return $this->bar + $this->baz;
}
}
Can we do that? How?
You need to implement the \Iterator or \IteratorAggregate interface to achieve that.
A simple example of what you're trying to achieve using the \IteratorAggregate and \Iterator interfaces (I've left out the \Iterator implementation details, but you can use the PHP doc to see how they work) :
class FooIterator implements \Iterator
{
private $source = [];
public function __construct(array $source)
{
$this->source = $source;
// Do whatever else you need
}
public function current() { ... }
public function key() { ... }
public function next()
{
// This function is invoked on each step of the iteration
}
public function rewind() { ... }
public function valid() { ... }
}
class Foo implements \IteratorAggregate
{
private $bar = [1, 2, 3];
private $baz = [4, 5, 6];
public function getIterator()
{
return new FooIterator(array_merge($this->bar, $this->baz));
}
}
$foo = new Foo();
foreach ($foo as $value) {
echo $value;
}
You need to implement the Iterator interface.
class Foo implements Iterator {
You should review the built in interfaces:
http://php.net/manual/en/reserved.interfaces.php

Simulating JavaScript extension functions

I was wondering if I can, in PHP, like JavaScript, apply a function call to the return of an object. In JavaScript I can do this:
var y = 1;
var x = y.toString().concat(' + 1');
console.log(x);
And I think if it is possible to do almost the same in PHP. I was thinking in recursion to this and I didn't know exactly the name to search for it. I'm trying, in the moment:
<?php
class Main {
public function __construct() {
$this->Main = new Main;
}
public function merge(/* this */ $xs, $ys) {
return array_merge($xs, $ys);
}
public function add(/* this */ $xs, $ys) {
return array_push($xs, $ys);
}
}
$aux = new Main;
$x = $aux -> merge([1, 2, 3], [4, 5, 6])
-> add(7)
-> add(8)
-> add(9);
// $x => [1, 2, 3, 4, 5, 6, 7, 8, 9]
?>
This is overflowing everything. I receive an overflow message:
Maximum function nesting level of '100' reached
Am I able to do this, like in JavaScript? Almost the same as C# extension methods.
Its called method chaining:
class Main {
private $ar = array();
public function merge($xs, $ys) {
$this->ar = array_merge($xs, $ys);
return $this;
}
public function add($ys) {
$this->ar[]= $ys;
return $this;
}
public function toArray(){
return $this->ar;
}
//if you want to echo a string representation
public function __toString(){
return implode(',', $this-ar);
}
}
$aux = new Main;
$x = $aux->merge([1, 2, 3], [4, 5, 6])->add(7)->add(8)-> add(9);
echo $x;
var_dump($x->toArray());
You can work with the returns from functions, but it’s not as nice-looking as JavaScript:
<?php
$array1 = array(1, 2, 3);
$array2 = array(4, 5, 6);
$x = array_push(array_push(array_push(array_merge($array1, $array2), 7), 8), 9);
$x should then be an array containing the numbers 1 through 9.

phpunit dbunit #dataProvider doesn't work

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.

Categories