How to define and code custom unit-test in raw PHP? - 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);

Related

php Slim framework - passing parameter to closure

I am trying to study the code for Slim framework. In the constructor for Slim class, $c is passed to the closure (for instance, when storing/setting the request/response object in the container):
public function __construct(array $userSettings = array())
{
// Setup IoC container
$this->container = new \Slim\Helper\Set();
$this->container['settings'] = array_merge(static::getDefaultSettings(), $userSettings);
// Default request
$this->container->singleton('request', function ($c) {
return new \Slim\Http\Request($c['environment']);
});
// Default response
$this->container->singleton('response', function ($c) {
return new \Slim\Http\Response();
});
But $c is not defined/declared anywhere prior to this statement, so how does it work? I started to trace everything from the beginning and I can't find $c anywhere prior to it being used in this manner.
$c is a parameter of the closure function. Imagine you had a function by itself:
function myFunction($c) {
echo $c;
}
In the case of a closure, you can store an anonymous function in a variable:
$someFunction = function ($c) {
echo $c;
}
$someFunction("hello world");
So instead of directly storing the closure into the variable, the code above is passing the anonymous function as a parameter to $this->container->singleton(). So $c is not created until the closure is called. The singleton method stores this in a variable called $value, so if that function ran:
$value(array('environment'=>'test'));
$c would now contain array('environment'=>'test')
Slim also uses the __get() __set() magic methods quite a bit, so from the example code you set, within the Slim class, one could call:
$request = $this->container->request(array('environment'=>'test'));
The container is of class Slim\Helper\Set. Since this doesn't have a request method, this would call the container's __get() method. It would look up the stored method configured above for 'request' and pass the array in as $c
I think khartnett gave a perfect answer. To make it clearer for you, an example.
When you define a function, you are only describing how it works. You are not setting any specific values. For example, when I write:
function sum($a, $b) {
return $a + $b;
}
I am not saying what the values of $a and $b are here. I am just describing what I am doing with these variables to calculate a result. It is not until I call this function that I'm working with actual values:
sum(3, 4); // returns 7
In your question, the $c variable is like the $a and $b variable.
Like khartnett showed in his answer, it works like this:
// Definition time
$someFunction = function ($c) {
echo $c;
}
// Calling time
$someFunction("hello world");
It is not until calling time that $c gets its value (in this example, the value is "hello world").
The $c is a reference to the container itself - so that any dependencies will be automatically resolved when invoked.
So using for example the request object:
// Default request
$this->container->singleton('request', function ($c) {
return new \Slim\Http\Request($c['environment']);
});
Looking at the Request constructor you will see that it expects an instance of Environment, which we just told the container should be available already using the key 'environment'.
The answer will lay in $app->run():
$this->container->get("service_name") then in get() method offsetGet($id)
public function offsetGet($id)
{
if (!isset($this->keys[$id])) {
throw new UnknownIdentifierException($id);
}
if (
isset($this->raw[$id])
|| !\is_object($this->values[$id])
|| isset($this->protected[$this->values[$id]])
|| !\method_exists($this->values[$id], '__invoke')
) {
return $this->values[$id];
}
if (isset($this->factories[$this->values[$id]])) {
return $this->values[$id]($this);
}
$raw = $this->values[$id];
$val = $this->values[$id] = $raw($this); // THIS LINE CALLS THE CONTAINER ITSELF
$this->raw[$id] = $raw;
$this->frozen[$id] = true;
return $val;
}
Pimple Container functioning it's a bit more complicated due to the fact:
Allowing any PHP callable leads to difficult to debug problems
as function names (strings) are callable (creating a function with
the same name as an existing parameter would break your container)
So unique identifiers are introduced.
Here is a simple implementation of ServiceContainer get() method inside the ServiceContainer class:
public function get($serviceName)
{
if (!array_key_exists($serviceName, $this->container)) {
throw new \http\Exception\InvalidArgumentException("Service not found!");
}
$service = $this->container[$serviceName];
if (is_callable($service)) {
$this->container[$serviceName] = $service = $service($this);
// $this (aka ServiceContainer) will be passed as parameter to Closures
}
return $service;
}
Hope it clarifies the question, have a nice day!

How to test if methods work TOGETHER well?

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?

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

Chained PHP controls

I'm making a form validation class and it works like this currently.
$validator->setVar($_POST['Username'])
->standardFilter(array('XSS', 'SQL_INJECTION'))
->customRegex()
->replace('This', 'With this')
->getResult();
While it works perfectly when chained like this, I can't archieve the following result.
$validator->setVar($_POST['Username'])
->isValidEmail()
->isValidPhoneNumber()
->isSet()
->isNull()
->getResult()
For example, script returns the following values
->isValidEmail() (true)
->isValidPhoneNumber() (true)
->isSet() (false)
Basically, I'm going to make an array, fill it with true/false depending on the result of each function, and I'll look for a specific value in array (a false). If it exists, the class will return false regardless of the rest of the chains. (or I can just override variables, not important here.)
However, I want $validator to stop chaining once it gets a false from a function. Let's say it received a false from isSet(). It shouldn't execute isNull() and getResult() since we already have a failed check.
How can I archieve this in PHP?
TL;DR:
var_dump($validator->setVar('Test message')->isInteger()->setTrue());
//false //true
Output: false, because once isInteger() failed, rest of the chain isn't executed.
How can I archieve this in PHP?
Nothing like good source code to learn from. I would suggest exploring the Zend Framework's Validation classes. It provides the same chaining functionality you describe.
...More source code check isValid() specifically.
Try something like this
class FooBar
{
private $SomethingWrong = false;
function Bar()
{
if( $this->SomethingWrong )
throw new Exception('SomeThing is wrong');
return $this;
}
function Foo()
{
return $this
}
}
$foobar = new FooBar();
$foobar->Bar()
->Foo();
The Foo() part will not be executed, because of the exception in the Bar().
Of course, there are some variations. If you do not want a exception, but a silent non-execute, you could try this:
class FooBar
{
private $SomethingWrong = false;
function Bar()
{
$this->SomethingWrong = true;
return $this;
}
function Foo()
{
if( !$this->SomethingWrong ) {
// do my stuff
}
return $this
}
}
The only way to do this, in any language, is to throw an exception. You can't return the validator object (which is necessary for chaining) and also return true or false, all while having the chaining work. That said, I am not advocating the use of exceptions in this manner. I am in complete agreement with vascowhite's comments below.
Rather than have it stop in the middle of the chain, why not consider the isSet, isNull, etc. methods as instructions to tell the validator what to check. Then have a validate method called at the end of the chain. The validate method can perform the validation based on the validator state (as set by the other methods). And that validate method can also return a true or a false, or a custom state object, with the result of the validation.
Instead of return a value, you can throw a custom exception, which abort the code execution.
Add an try-catch block to the code, handle your exception and everything works fine.
EDIT:
What you also can do is a little bit magic and not really to be recommed. But nice to know, this is possible in php, so better use Exceptions
class PassThroughValidator extends ...
{
private $val;
public function __construct($result)
{
$this->val = $result;
}
public function __call($name, $arguments)
{
return $this;
}
public function getResult()
{
return $this->val;
}
}
class EmailValidator extends ...
{
function isMail()
{
if (...) {
// do something here
return $this;
}
// set Result to false or something similar
return new PassThroughValidator($this->getResult());
}
}
Considering that the value returned in each step of the chain is an object, you can not have one of the chained methods return true/false. it must always return an object instance. So I guess what you would need to do is add some property on the object to indicate that validations should not be done, and if the property is set, just ignore the validation attempt and return the object as is.
So perhaps something like this in simplified form, showing only one such validation:
class validator {
protected $ignore_validations = false;
protected $value = null;
protected $is_null;
public function isNull () {
if(true === $this->ignore_validations) {
return $this;
} else if(is_null($this->value)) {
$this->is_null = true;
$this->ignore_validations = true;
return $this;
} else {
$this->is_null = false;
return $this;
}
}
}

Instancing an object and calling a method in one line?

php 5.3
Is there a way to do this (viable in java for example)
(new MyClass())->myMethod();
i am receving: Parse error: syntax error, unexpected T_OBJECT_OPERATOR in D.. on line 7
Add
I really need that RFC to be implemented in the next PHP version!
http://wiki.php.net/rfc/instance-method-call
Is there a way we can subscribe to it so it can get more attention?
No, its not possible. There is a RFC for that
http://wiki.php.net/rfc/instance-method-call
But no one knows, when this will come to the userland.
Jacob mentioned the static method. There are other more or less useful methods to achieve the same
function instanciate($className, $arg1 = null) {
$args = func_get_args();
array_shift($args);
$c = new ReflectionClass($className);
return $c->newInstanceArgs($c);
}
instanciate('Classname', 1, 2, 3)->doSomething();
However, I prefer the temporary variable (like in the question).
Update:
I can swear there where an example for the temporary variable stuff in the question in the past. However, I meant this
$x = new Class;
$x->method();
where $x is the temporary variable.
That is not valid syntax. A handy way to achieve what you want is to use a static method to create the object.
In your MyClass:
public static function create() {
return new MyClass();
}
Then you can use:
MyClass::create()->myMethod();
However it is extra code that you have to maintain, if for example the constructor is changed or the class is extended. So you need to weigh up the benefits.
You can do something like this:
function chain_statements($statement1, $statement2) { return $statement2; }
class TClass { public Method() { ...; return $this; } }
$b = chain_statements($a = new TClass(), $a->Method());
... or more generalized:
function chain_statements(array $statements) { return end($statements); }
For example:
function chain_statements($statement1, $statement2) { return $statement2; }
function chain_statements2(array $statements) { return end($statements); }
class TClass
{
public $a = 0;
public function Method1() { $this->a = $this->a + 1; return $this; }
public function Method2() { $this->a = $this->a + 2; return $this; }
}
$b = chain_statements($c = new TClass(), $c->Method1()); echo($b->a);
$b = chain_statements2(array($c = new TClass(), $c->Method1(), $c->Method2())); echo($b->a);
... or even better:
function call_method($object) { return $object; }
$b = call_method(new TClass())->Method2(); echo($b->a);
Not as such. In PHP new is not an expression, but a language construct. The common workaround is to provide a static instantiation method for MyClass::get()->... use.
A more concise alternative is a hybrid factory function:
function MyClass() { return new MyClass; }
class MyClass {
...
}
Which then simplifies the instantiation to MyClass()->doSomething();
You can put it in one statement if you really wanted to. Use eval() ;p
But you probably shouldn't.
I had this same problem a while ago but I found this simple solution which is pretty readable too. I like the fact it uses only the standard PHP functions. There's no need to create any utility functions of your own.
call_user_func(
array(new ClassToInstance(), 'MethodName'),
'Method arguments', 'go here'
);
You can also use call_user_func_array to pass the arguments as an array.
call_user_func_array(
array(new ClassToInstance(), 'MethodName'),
array('Method arguments', 'go here')
);

Categories