How to test if methods work TOGETHER well? - php

class to test:
class TestMe
{
public function add ($a, $b)
{
return $a + $b;
}
public function mul ($a, $b)
{
return $a * $b;
}
public function sumAddMul ($a, b)
{
$i = $this->add ($a, $b);
$j = $this->mul ($a, $b);
return $i + $j;
}
}
testclass:
public function testAdd()
{
$sut = new TestMe();
$this->assertEquals (9, $sut->add(4,5));
}
public function testAdd()
{
$sut = new TestMe();
$this->assertEquals (8, $sut->mul(4,2));
}
public function testSumAndMul()
{
?
}
so, how to test sumAndMul()? Of course, I can write:
public function testSumAndMul()
{
$this->assertEquals (3, $this->sut->sumAndMul(1,1));
}
the problem is its like testing something again what has been tested already. Its rather testing something that cooperating each other.

Seeing a real life example would make more sense I'm guessing. But the way you've suggested is probably the best when you have more complex functions and more complex tests. Of course in the given instance you can just do the following to kill three birds with one stone:
public function testSumAndMul()
{
$sum = $sut->add(1, 1);
$mul = $sut->mul(1, 1);
$sumAndMul = $sut->sumAndMul(1, 1);
$this->assertEquals(2, $sum);
$this->assertEquals(1, $mul);
$this->assertEquals(3, $sumAndMul);
}
Unit testing is about testing the possible smallest units. When you start testing bigger chunks you start deviating from the rule. Keeping each test as independent as possible would be without a doubt the best approach.

Don't worry so much that sumAndMul() internally calls other methods here, given that there's no internal logic which changes its behaviour based in inputs (if that makes sense).
Just test that it returns a predictable value: eg: if you pass it 17 and 19 you get 359 back out.
Ask yourself if you really care how the method under test arrives at its result, or whether it's that it does arrive at its result (and what the result is) that matters.
I don't think it matters to sumAndMul() that internally it calls add() and mul()? Obviously these are example methods, so seeing the actual situation might be helpful here?

Related

How to define and code custom unit-test in raw PHP?

I am using some special PHP framework. I can't use any unit-test frameworks by some reasons like PHPunit or codeception. So i need to write my custom code to achieve that. Is there any examples could finish the job?
Can i use this method instead of using framework?
public function testFailure()
{
$a = 1; $b = 0;
if($a !=== b){
//throw exception here
}
}
Instead-
public function testFailure()
{
$this->assertEquals(1, 0); //return false
}
The absolutely easiest way would be pretty much what you wrote above (although the code is not really valid). Throw an exception on assertions and you have a valid way of unit testing!
Now, I would think that you could probably use something like phpunit weather or not you are using some custom code, but I won't push on that more than letting you know.
Also:
!=== is invalid, !== would be more correct!
Further on, I'd recommend that you create some type of static or global methods for your assertions instead of the above, that way you can easily re-use the exception throwing code instead of writing the same over and over:
// assert.php
class Assert {
public static function isEqual($a, $b) {
if ($a != $b) {
throw new MyAssertionException('Not equal!');
}
return true;
}
public static function isSame($a, $b) {
if ($a !== $b) {
throw new MyAssertionException('Not same!');
}
return true;
}
}
---
// test.php
include_once 'assert.php';
Assert::isEqual(1, 2);

Defining short, private PHP nested functions (sub-functions) - best performance? best practice?

When creating a simple function, it is sometimes appropriate to encapsulate a small section of logic in a sub-function. My question is:
Assuming we will never use the calc function again, which of the following is easiest on the PHP parser when running this type of procedure?
1. A Nested Function: (PHP has to redefine calc each time:)
function doSomething($a, $b, $c) {
$calc = function($val) { /* do some calculation */ };
if($a>$c) return $calc($c);
else if($a<$b) return $calc($b);
else return $calc($c);
}
2. A Second Function: (PHP has to keep calc in global memory:)
function doSomething($a, $b, $c) {
if($a>$c) return calc($c);
else if($a<$b) return calc($b);
else return calc($c);
}
function calc($val) { /* do some calculation */ }
3. A Class: (More code, and still in global memory)
class something {
static public function doSomething($a, $b, $c) {
if($a>$c) return self::calc($c);
else if($a<$b) return self::calc($b);
else return self::calc($c);
}
static private function calc($val) { /* do some calculation */ }
}
Check this answer: anonymous function performance in PHP
As it states it usually does not make much of a difference. If you want to be sure: a lot depends on your specific PHP and server version so you will have to benchmark it.
Having said that, version 2 is more readable than version 1, but version 3 - a class with private function would be the most readable solution as your code tells other programmers clearly that calc() is not used elsewhere.
class something {
static public function doSomething($a, $b, $c) {
if($a>$c) return self::calc($c);
else if($a<$b) return self::calc($b);
else return self::calc($c);
}
static private function calc($val) { /* do some calculation */ }
}

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

PHP modify code to avoid anonymous functions

I've found some solutions to a sorting problem I've been having, but the code uses anonymous functions in PHP. Im using version 5.2.17 and I believe anonymous functions are not supported.
How would I change the following blocks of code so I can use them in PHP 5.2.17
$keys = array_flip($order);
usort($items, function($a, $b) use($keys)
{
return $keys[$a['id']] - $keys[$b['id']];
});
from PHP sort multidimensional array by other array
And
$sorted = array_map(function($v) use ($data) {
return $data[$v - 1];
}, $order);
from PHP - Sort multi-dimensional array by another array
UPDATE:
One of the problems is I'm not sure how the variables $a, $b and $v are used. So I'm not sure how to create normal functions, thus bypassing the anon functions.
Both of the anonymous functions make use of the use clause to pass variables into the local scope.
You can achieve the same with object methods in which the objects have those variables as properties.
Inside the object method you then can access these.
$sorted = array_map(function($v) use ($data) {
return $data[$v - 1];
}, $order);
An exemplary mapping object then could look like:
class MapObj
{
private $data;
public function __construct($data) {
$this->data = $data;
}
public function callback($v) {
return $this->data[$v - 1];
}
}
As you can see it has the same functionality but just written in PHP 5.2 syntax.
And it's usage:
$map = new MapObj($data);
$callback = array($map, 'callback');
$sorted = array_map($callback, $order);
And that's how it works. Callbacks for object methods are always written in form of an array with two members, the first one is the object instance, and the second one is the name of the object method.
Naturally you can extend this an put the mapping function into the mapping object, so it's more straight forward:
class MapObj
{
...
public function map(array $order) {
$callback = array($this, 'callback');
return array_map($callback, $order);
}
}
New usage:
$map = new MapObj($data);
$sorted = $map->map($order);
As you can see this might make the usage a bit more straight forward. I must admit, my method naming is not really brilliant here, so I leave some room for your improvements.
Another benefit is, you can make the visibility of the callback method private then.
The situation with passing the data to work with in the callback as a parameter to the mapping function. That is because you wrote you already have a class that you want to make use of, but you can not touch the constructor. So the given example is a bit short.
Here is another example without using the constructor, I removed it:
class MyObj
{
private $data;
private function callback($v) {
return $this->data[$v - 1];
}
public function map($order, $data) {
$callback = array($this, 'callback');
$this->data = $data;
return array_map($callback, $order);
}
}
As you can see, the constructor is not needed any longer to pass the $data, but instead it's just passed into the map() method as an additional parameter. Usage:
$myObj = new MyObj(....); // somewhere.
// later on:
$myObj->map($order, $data);
// could be also:
$this->map($order, $data);
As you can see, how you set the private member variable is up to you. Do what fits the job.
What you have here is a closure over $data -- it's not 100% possible to rewrite it without an anonymous function. Here's the closest possible approximation:
function _array_sort_callback($a, $b) {
global $_array_sort_callback__keys;
return $_array_sort_callback__keys[$a['id']] - $_array_sort_callback__keys[$b['id']];
}
... {
$keys = array_flip($order);
global $_array_sort_callback__keys;
$_array_sort_callback__keys = $keys;
usort($items, "_array_sort_callback");
}
Note that I've prefixed the name of the global to try to avoid a collision. Both the function name and the global name need to be unique within your application.
Also, keep in mind that PHP 5.2.17 is obsolete and unsupported. You should migrate off of it as soon as possible.
If you want to mimic a closure, where you snapshot variables at a specific time, you can use a simple base class to serve as a container for the values, and then just define sub classes to implement the comparison logic.
Untested
// base class exists purely to capture the value of some variables at instantiation time
// kinda like a closure
class VarCapture {
protected $vars;
function __construct($vars) {
$this->vars = $vars;
}
}
class ItemComparer extends VarCapture {
function compare($a, $b) {
$keys = $this->vars['keys'];
return $keys[$a['id']] - $keys[$b['id']];
}
}
class PluckMapper extends VarCapture {
function pluck($v) {
$data = $this->vars['data'];
return $data[$v - 1];
}
}
$keys = array_flip($order);
$ic = new ItemComparer(compact('keys'));
$callable = array($ic, 'compare');
usort($items, $callable);
$pm = new PluckMapper(compact('data'));
$callable = array($mp, 'pluck');
$sorted = array_map($callable, $order);
Note that I made use of php's callback psuedo type
http://php.net/manual/en/language.types.callable.php
You can also re-write it into pre-5.3 anonymous functions, a la create_function(). Although create_function() functions don't normally act as closures, you can use some tricks (without using global variables) to make them work as closures in some limited circumstances. You encode the closed-over variables directly into the source of the function. The limitations are that data only goes one-way -- in; closed-over variables can only be "simple" data types, like numbers, strings, and arrays; and functions created with create_function are never deallocated, leaking memory; plus it is not very efficient. But I think it is sufficient for your example (assuming you only use arrays and strings and such).
$keys = array_flip($order);
usort($items, create_function('$a,$b', '$keys = '.var_export($keys,true).';
return $keys[$a["id"]] - $keys[$b["id"]];
'));
and
$sorted = array_map(create_function('$v', '$data = '.var_export($data,true).';
return $data[$v - 1];
'), $order);
The more general pre-5.3 solution, though, is to use an object and method as the closure, as in hakra's answer.

PHP: compareTo similar to Java

In an effort to utilize OOP in PHP, I was looking for a way to define functions within objects to use for sorting. in Java this is simple, as the compareTo() is automatically called by sorted arrays and such. I looked around PHP.net and couldn't find anything similar in PHP. I have resorted to what seems like a hack to me, so I'm wondering if anyone can lend some insight on an easier way.
CURRENT CODE:
class SomeObject {
private $someField;
function getSomeField() { return $this->someField; }
function compareTo($other) {
return $this->someField - $other->getSomeField();
}
}
//in funcs.php
function objSort($a, $b) {
return $a->compareTo($b);
}
//To sort an array
usort($array, objSort);
Is there an easier/more sleek way of doing this in PHP?
You could use anonymous function directly.
class SomeObject {
private $someField;
function getSomeField() { return $this->someField; }
}
usort($array, function($a, $b) {
return $a->getSomeField() - $b->getSomeField();
});
Or you could define a static function use to compare.
class SomeObject {
private $someField;
function getSomeField() { return $this->someField; }
static function compare($a, $b) {
return $a->getSomeField() - $b->getSomeField();
}
}
usort($array, array('SomeObject', 'compare'));
I don't think you can do this in PHP, although I would love to be proved wrong. I usually have a package of utility classes for arrays, strings, numbers, etc. with static methods, but it's only useful if you are defining functions that PHP doesn't already have, as you are otherwise just making pointless wrappers for native functions.

Categories