Mock object and retain functionality of other methods - php

Say for example I have this class:
class Foo {
public function add($x, $y)
{
return $x + $y;
}
public function subtract($x, $y)
{
return $x - $y;
}
}
and I wanted to change the behavior of the add method only:
$mock = $this->getMock('Foo');
$mock->expects($this->once())->method('add')->will($this->returnCallback(function ($x, $y) {
return ($x + 0) + ($y + 0);
}));
$this->assertEquals(4, $mock->add(2,2));
$this->assertEquals(2, $mock->subtract(4,2));
Why is my subtract method now returning null? I was expecting it to behave usual.
Failed asserting that null matches expected 2.

You need to do a partial mock specifying to getMock what method you want to mock:
$mock = $this->getMock('Foo', array('add');
In this way only the add method is mocked, the rest of the object is behaving as usual.

Use like this:
$mock = m::mock('Foo[add]');

Related

How to mock inner function in phpunit?

This is my Foo class
<?php
class FooClass
{
public function doFoo($total)
{
$gst = (($this->getTaxRate() / 100) * $total);
return $gst;
}
public function getTaxRate()
{
return 5;
}
}
And this is my test.
public function fooTest()
{
$mockedObj = $this->createMock(FooClass::class);
$mockedObj->expects($this->exactly(1))
->method('getTaxRate')
->will($this->returnValue(10));
$this->assertEquals(10, $mockedObj->doFoo(100));
}
Output:
Failed asserting that null matches expected 10.
I can see getTaxRate() function is not being mocked .It is also returning null instead of 5(default value). I am expecting getTaxRate() inside doFoo() to return the mock value i.e 10 else if I do not mock a getTaxRate, it should return 5.
Anything that I am missing here?

Vector calculations class oop php

I'm learning php oop and seems like i still do not understand of how some things work as my code, which, imo, looks properly doesn't work and returns few errors. This is the code:
<?php
class Vector {
private $x;
private $y;
public function __construct($x, $y) {
if (is_nan($x) || is_nan($y)) {
$this->x = 0 && $this->y = 0;
} else {
$this->set($x, $y);
}
}
public function __destruct() {
var_dump($x, $y);
}
public function setx($x) {
if (is_numeric($x)) {
$this->x;
}
}
public function sety($y) {
if (is_numeric($y)) {
$this->y;
}
}
public function retLength() {
return $x;
}
public function addVector() {
$sum=$x+$y;
}
public function dotProduct() {
$dot_product = array_sum(array_map(function($x,$y) { return $x*$y; }, $array1, $array2));
}
}
$wekt= new Vector($x, $y);
echo $wekt->addVector(5,7);
Errors i get are: undefined variables "x" and "y" on line 42 (which is $wekt= new Vector($x, $y); ) and "Call to undefined method Vector::set()".
Specification for this class is:
two private attributes $x and $y (seems to be ok)
constructor receives $x and $y and on receive checks if these are numbers. Constructor is supposed to output message about just created vector.
I do not understand much all this constructor and probably this is one of reasons why this code doesn't work as it is intended to.
destructor is supposed to output info about destroyed object.
there should be available functions to change values of $x and $y
there should be available function to return $x
two more functions: one outputting sum of two vectors, second function supposed to output scalar product which takes as value a number.
There are two things in your code going wrong. See the following code:
class Vector {}
$wekt= new Vector($x, $y);
echo $wekt->addVector(5,7);
Where are $x and $y defined? This is the main reason you are getting the error. You class has a different scope then the global scope, meaning everything you define there is only accessible by $wekt-> as $wekt is defined in the global scope.
Now the second thing is addVector():
echo $wekt->addVector(5,7);
You ask to echo the return of this method, yet no return is defined in that function. Secondly where is the $x and $y defined within the scope of that function?
Change it to something like:
class Vector {
private $list = [];
public function addVector($x, $y) {
$this->list[] = new Vector($x, $y);
return $x + $y;
}
}

Closures in a class and protected methods

Its not clear to me if the following would work:
class Sample {
private $value = 10;
public function something() {
return function() {
echo $this->value;
$this->someProtectedMethod();
}
}
protected function someProtectedMethod() {
echo 'hello world';
}
}
I am using PHP 5.6, the environment this would run is 5.6. I am not sure about two things, the scope of this. and if I can call protected methods, private methods and private variables inside of closure functions.
Problem #1 is a simple syntax error:
return function() {
echo $this->value;
$this->someProtectedMethod();
};
(note the semi-colon)
Now this code will return the actual function when you call something().... it will not execute the function, so you'll want to assign that function to a variable. You have to make an explicit call to that variable as a function to execute it.
// Instantiate our Sample object
$x = new Sample();
// Call something() to return the closure, and assign that closure to $g
$g = $x->something();
// Execute $g
$g();
Then you get into issues of scope, because $this isn't in scope of the function when $g is called. You need to bind the Sample object that we've instantiated to the closure to provide scope for $this, so we actually need to use
// Instantiate our Sample object
$x = new Sample();
// Call something() to return the closure, and assign that closure to $g
$g = $x->something();
// Bind our instance $x to the closure $g, providing scope for $this inside the closure
$g = Closure::bind($g, $x)
// Execute $g
$g();
EDIT
Working Demo

Define arity of an anonymous function without code generation

It is possible to determine how many arguments a function accepts by using reflection.
I want to be able to define a function compose that performs function composition. That is to say, compose($f, $g) should produce a new function that returns $f($g($x)).
I have a sample implementation here:
function compose()
{
$fns = func_get_args();
$prev = array_shift($fns);
foreach ($fns as $fn) {
$prev = function ($x) use ($fn, $prev) {
$args = func_get_args();
return $prev(call_user_func_array($fn, $args));
};
}
return $prev;
}
When composing $f and $g, $g may have an arity higher than 1. Which means it can take more than one argument. Thus, the function returned by compose($f, $g) may also take more than one argument -- it takes exactly the same arguments as $g.
The problem with this implementation is that there is no way to control the exposed arity of what compose returns. In this case it is always 1, because of the function ($x) .... When trying to determine the arity using reflection, it will always return 1 instead of that of $g.
Is there a way to change the amount of arguments of an anonymous function seen by PHP's reflection system, without using eval and other code generation techniques?
The moment you introduce func_get_args() into a function should invalidate any hope of being able to determine its true arity. At that point, the arity is really only defined by the function's logic, and cannot be determined by reflection or static code analysis.
I've written a compose-like implementation before, but it just assumed that the functions you are composing both have an arity of 1.
Here is an ugly solution as it does not work with all number of parameters (or you end up with tons of case stuff), but it does not rely on eval:
function compose($f, $g)
{
switch(getReflectiveArity($g)) {
case 1:
return function($x) use ($f, $g) {
return $f($g($x));
};
break;
case 2:
return function($x, $y) use ($f, $g) {
return $f($g($x));
};
break;
case 3:
return function($x, $y, $z) use ($f, $g) {
return $f($g($x, $y, $z));
};
break;
/* ... */
default:
throw new RuntimeException();
}
}
My proposed solution to this would be to introduce a custom convention for specifying the arity using a custom property, defined on an object that wraps the closure.
Like this:
class CustomArityFunction
{
public $f;
public $arity;
function __construct(callable $f, $arity)
{
$this->f = $f;
$this->arity = $arity;
}
function __invoke()
{
return call_user_func_array($this->f, func_get_args());
}
}
// define function
$f = function () { ... };
return new CustomArityFunction($f, $n);
// determine arity
$arity = ($f instanceof CustomArityFunction) ? $f->arity : getReflectiveArity($f);
The major downside of this solution is that the consuming code needs to be aware of the convention.
It is however the cleanest way of doing this that I could come up with.
Note: The wrapper is needed because PHP does not allow assigning properties to closures. Thanks to #nikic for pointing that out.
Based upon How can I dynamically check the number of arguments expected of an anonymous function in PHP?
is the following piece of code which works on php >= 5.3
http://3v4l.org/6KPFN
Update: Just reread the question ... this is probably BS

how to access variable of a method

I have this class and I want to get the values in second method runSecond from Gettest method. How would I do that?
class Test {
public static function Gettest($x, $y, $z){
$x = $x;
$x = $x . basename($y);
self::runSecond();
}
private function runSecond(){
//how do I access $x here? I need to know the value of $x, $y and $z here
// and I dont want to pass it like this self::runSecond($x, $y, $z)
}
}
Why do you not want to pass the values into your second method?
Method parameters are the accepted way of doing this.
The only other option you have is to use global or member variables, but for something like this I would highly suggest parameters instead. There is no good reason I can see not to.
If you really, absolutely, have to do this (and I still don't see why), you can use a private member variable like this:
class Test {
private $x;
private $y;
private $z;
public static function Gettest($x, $y, $z){
$x = $x;
$x = $x . basename($y);
$test = new Test();
$test->x = $x;
$test->y = $y;
$test->z = $z;
$test->runSecond();
}
private function runSecond(){
$this->x;
$this->y;
$this->z;
}
}
Note that you have to create an instance of the class to call the second method. Your original way of using self:: would not work to call a non static method, even if you did pass the values as parameters.

Categories