Unit testing of functions - php

I have got a PHP file in which there are some functions (not included in a class). I am using PHPUnit to testing. When I try to generate in a simply way a test file from a file containing functions, the log says:
Could not find class...
Is there any possibility to test functions which are not methods?

Yes, you can with something like this:
includes/functions.php
function my_function() {
return true;
}
tests/MyFunctionTest.php
require_once '../includes/functions.php';
class MyFunctionTest extends PHPUnit_Framework_TestCase
{
public function testReturnValue()
{
$return_value = my_function();
$this->assertTrue($return_value);
}
}
So as long as your function is within scope you can call it from your test method just like any other PHP function in any other PHP framework or project.

If I'm right then PhpUnit works only with classes hence methods. So just convert them into the methods for testing purpose. Shouldn't be hard.

Related

PHPUnit: How to test a method which calls another function declared in different file

I'm trying to test a method using PHPUnit, where it calls another function (standalone function, without class), which resides in different file which does a some pretty good calculation and returns a object.
This is my actual main code:
class CreateRecords
{
public function createEntities($details)
{
if (trim($details['username']) == "") {
$this->result = "Username is empty.";
} else {
$this->result = create_record($Details['username']);
}
return $this->result;
}
}
This create_record function, (standalone function, without class), which is core function, resides in separate file and it does pretty good calculations (calls lots of other methods/functions) and returns object, whether it is successful or not.
I can mock the createEntities method, but I want to mock the create_record function, which does all the computations and returns the result.
I have seen few posts which has a somewhat similar scenario,
phpunit testing method that calls other class methods which need mock
PHPUnit mock method used in another class
But I am unable to understand, how to mock standalone function which is declared in some different file.
You can create new method that will be returning result from outside function.
Then you can mock this new method
class CreateRecords
{
public function createEntities($details)
{
if (trim($details['username']) == "") {
$this->result = "Username is empty.";
} else {
$this->result = $this->createRecord($Details['username']);
}
return $this->result;
}
public function createRecord($username){
return create_record($username);
}
}
Namespaces in PHP5.3+ offer an excellent solution to this, which allows you to override built-in functions in your current namespace.
Longer term, refactoring the global create_record() into a class which can be injected into your CreateRecords class, and then mocked, would be a good way to go. In this instance, the global function would just be a simple wrapper to call the class until the entire application was updated.
To re-create the create_record($username) is not hard though, and useful for tests. The same technique can be used to override the global time() function as well.
Within the test-file, add a new (but local) namespace:
<?php
namespace Test\DatabaseAccess;
use DatabaseAccess\CreateRecord;
use PHPUnit\Framework\TestCase;
namespace DatabaseAccess {
function create_record($username)
{
// pretend to do something
}
}
class CreateRecordTest extends TestCase
{
// test to check CreateRecord class
// which should call the `create_record`, above
}
This is the same technique that the SymfonyBridge system uses to create ClockMock - which dynamically adds time(), sleep(), etc to the namespace that you are unit-testing (in this example, the namespace DatabaseAccess\CreateRecord, not the Test\ prefixed namespace). ClockMock (and DnsMock) does it with an eval() call, but since you know the namespace explicitly, you can write it into the test file itself for clarity.
After reading the above (pretty good) answers and your comments saying that you cannot touch the tested class - CreateRecords,
I can suggest another solution that is not ideal but should get the job done:
Create a new class that inherits\ extends from CreateRecords - CreateRecordsExtended.
The extended class should override only the tested function in question createEntities($details). so create a new one and copy the code from the original function.
Also, create a new function create_record().
Now, inside the new createEntitied, call your version of create_record - $this->create_record(), instead of calling the global function.
Now you can mock it! and even because this class is used only for testing, you can even just retun whatever you want from it, and do not even have to mock it now.
This class can reside either in the regular code folder, or as a neighbor of your testing class- as it is used only for testing.
Pros:
existing code is not modified at all.
you still use same exact
functionality, besides the mocked function, which is what you wanted.
Cons:
you will be testing a different class then the one you wanted to, but
it still close enough.
code inside function createEntities needs to
be copied
Perhaps its not most ideal, but should get the job done. hope i helped.

Running code in a PHP once

I'm trying to write a class in PHP that acts as a wrapper for a collection of command line tools to make them easier to use from PHP.
I have a single class (MyClass) in a file myclass.php.
I have code that checks to see if the required tools are installed and then sets a constant (TOOLS_AVAILABLE) to either true or false. Although it's not a lot of code, I only want it to run the first time somebody tries to instantiate my class or use any of its static functions. What's the best practice for handling this?
I only want it to run the first time somebody tries to instantiate my class or use any of its static functions.
Well, the best answer is not to have any static methods. Then you can stick the code in a constructor method as per the answer by #treegarden.
If you must have static methods, then you'll need a static flag within the class to indicate when you've called the 'run once' code, so you can avoid running it again. And then call it explicitly from each of your static methods and the constructor. Something like this:
<?php
class myClass {
private static $hasRunOnce = false;
private static runMeOnce()
{
if (!self::$hasRunOnce) {
self::$hasRunOnce = true;
//put your 'run once' code here...
}
}
public static oneOfYourStaticMethods()
{
self::runMeOnce();
//put your static method code here...
//this would be the same for each of your static methods and your constructor.
}
}
Hope that helps.
You need to create a __construct function in your class and put whatever code you want to execute on instantiation in there:
class MyClass {
function __construct(/* arguments */) {
/* your code here */
}
}
The code will get executed only once when someone instantiates the class.

How to handle a call to an undefined function in a PHP unit test

I am relatively new to unit testing, so maybe someone can help me out here.
Problem
The following error message appears when executing the PHP unit test in the terminal:
Fatal error: Call to undefined function Path\to\missing_function() in /path/to/file.php on line 123
Normally, I would now create a dummy object using the getMock(originalClassName) function and then predefine what should be returned for missing_function() but sadly the function is not placed in any interface/class like all other functions I tested up to now.
Anyone got an idea here? Cheerio!
Generally speaking, you would just include the file with the function and have it get executed. Then you just make sure that after your code was executed, what was supposed to happen happens. You are more concerned with the outcome of the code that you are testing rather than the process of how your code is executed.
Though, if you need to mock a function there is a way using namespaces (need PHP 5.3+). In your test file, you can place a "mock" function that is in the same namespace as your code. When the function gets called php looks in the current namespace first and will find your replacement function. In the normal running of your code, it will proceed to the global namespace to call your function.
So you code would end up like this:
Your class:
namespace Foo;
class SUT {
public function bar() {
return baz();
}
}
Your test:
namespace Foo;
function bar() {
return 'boz';
}
class SUTTest extends PHPUnit_Framework_TestCase {
public function testBar() {
$sut = new SUT();
$this->assertEquals('boz', $sut->bar());
}
}

Is it possible to overwrite a function in PHP

Can you declare a function like this...
function ihatefooexamples(){
return "boo-foo!";
};
And then redeclare it somewhat like this...
if ($_GET['foolevel'] == 10){
function ihatefooexamples(){
return "really boo-foo";
};
};
Is it possible to overwrite a function that way?
Any way?
Edit
To address comments that this answer doesn't directly address the
original question. If you got here from a Google Search, start here
There is a function available called override_function that actually fits the bill. However, given that this function is part of The Advanced PHP Debugger extension, it's hard to make an argument that override_function() is intended for production use. Therefore, I would say "No", it is not possible to overwrite a function with the intent that the original questioner had in mind.
Original Answer
This is where you should take advantage of OOP, specifically polymorphism.
interface Fooable
{
public function ihatefooexamples();
}
class Foo implements Fooable
{
public function ihatefooexamples()
{
return "boo-foo!";
}
}
class FooBar implements Fooable
{
public function ihatefooexamples()
{
return "really boo-foo";
}
}
$foo = new Foo();
if (10 == $_GET['foolevel']) {
$foo = new FooBar();
}
echo $foo->ihatefooexamples();
Monkey patch in namespace php >= 5.3
A less evasive method than modifying the interpreter is the monkey patch.
Monkey patching is the art of replacing the actual implementation with a similar "patch" of your own.
Ninja skills
Before you can monkey patch like a PHP Ninja we first have to understand PHPs namespaces.
Since PHP 5.3 we got introduced to namespaces which you might at first glance denote to be equivalent to something like java packages perhaps, but it's not quite the same. Namespaces, in PHP, is a way to encapsulate scope by creating a hierarchy of focus, especially for functions and constants. As this topic, fallback to global functions, aims to explain.
If you don't provide a namespace when calling a function, PHP first looks in the current namespace then moves down the hierarchy until it finds the first function declared within that prefixed namespace and executes that. For our example if you are calling print_r(); from namespace My\Awesome\Namespace; What PHP does is to first look for a function called My\Awesome\Namespace\print_r(); then My\Awesome\print_r(); then My\print_r(); until it finds the PHP built in function in the global namespace \print_r();.
You will not be able to define a function print_r($object) {} in the global namespace because this will cause a name collision since a function with that name already exists.
Expect a fatal error to the likes of:
Fatal error: Cannot redeclare print_r()
But nothing stops you, however, from doing just that within the scope of a namespace.
Patching the monkey
Say you have a script using several print_r(); calls.
Example:
<?php
print_r($some_object);
// do some stuff
print_r($another_object);
// do some other stuff
print_r($data_object);
// do more stuff
print_r($debug_object);
But you later change your mind and you want the output wrapped in <pre></pre> tags instead. Ever happened to you?
Before you go and change every call to print_r(); consider monkey patching instead.
Example:
<?php
namespace MyNamespace {
function print_r($object)
{
echo "<pre>", \print_r($object, true), "</pre>";
}
print_r($some_object);
// do some stuff
print_r($another_object);
// do some other stuff
print_r($data_object);
// do more stuff
print_r($debug_object);
}
Your script will now be using MyNamespace\print_r(); instead of the global \print_r();
Works great for mocking unit tests.
nJoy!
Have a look at override_function to override the functions.
override_function — Overrides built-in
functions
Example:
override_function('test', '$a,$b', 'echo "DOING TEST"; return $a * $b;');
short answer is no, you can't overwrite a function once its in the PHP function scope.
your best of using anonymous functions like so
$ihatefooexamples = function()
{
return "boo-foo!";
}
//...
unset($ihatefooexamples);
$ihatefooexamples = function()
{
return "really boo-foo";
}
http://php.net/manual/en/functions.anonymous.php
You cannot redeclare any functions in PHP. You can, however, override them. Check out overriding functions as well as renaming functions in order to save the function you're overriding if you want.
So, keep in mind that when you override a function, you lose it. You may want to consider keeping it, but in a different name. Just saying.
Also, if these are functions in classes that you're wanting to override, you would just need to create a subclass and redeclare the function in your class without having to do rename_function and override_function.
Example:
rename_function('mysql_connect', 'original_mysql_connect' );
override_function('mysql_connect', '$a,$b', 'echo "DOING MY FUNCTION INSTEAD"; return $a * $b;');
I would include all functions of one case in an include file, and the others in another include.
For instance simple.inc would contain function boofoo() { simple } and really.inc would contain function boofoo() { really }
It helps the readability / maintenance of your program, having all functions of the same kind in the same inc.
Then at the top of your main module
if ($_GET['foolevel'] == 10) {
include "really.inc";
}
else {
include "simple.inc";
}
You could use the PECL extension
runkit_function_redefine — Replace a function definition with a new implementation
but that is bad practise in my opinion. You are using functions, but check out the Decorator design pattern. Can borrow the basic idea from it.
No this will be a problem.
PHP Variable Functions
Depending on situation where you need this, maybe you can use anonymous functions like this:
$greet = function($name)
{
echo('Hello ' . $name);
};
$greet('World');
...then you can set new function to the given variable any time
A solution for the related case where you have an include file A that you can edit and want to override some of its functions in an include file B (or the main file):
Main File:
<?php
$Override=true; // An argument used in A.php
include ("A.php");
include ("B.php");
F1();
?>
Include File A:
<?php
if (!#$Override) {
function F1 () {echo "This is F1() in A";}
}
?>
Include File B:
<?php
function F1 () {echo "This is F1() in B";}
?>
Browsing to the main file displays "This is F1() in B".

test php functions (not classes) with netbeans and PHPUnit

I'd like to run unit test for a functions library file...
that is, I don't have a class, it's just a file with helper functions in it...
for example, I've created a php project at ~/www/test
and a file ~/www/test/lib/format.php
<?php
function toUpper( $text ) {
return strtoupper( $text );
}
function toLower( $text ) {
return strtolower( $text );
}
function toProper( $text ) {
return toUpper( substr( $text, 0, 1 ) ) . toLower( substr( $text, 1) );
}
?>
tools -> create PHPUnit tests gives me the following error:
PHPUnit 3.4.5 by Sebastian Bergmann.
Could not find class "format" in
"/home/sas/www/test/lib/format.php".
now, if I code (by hand!) the file
~/www/test/tests/lib/FormatTest.php
<?php
require_once 'PHPUnit/Framework.php';
require_once dirname(__FILE__).'/../../lib/format.php';
class FormatTest extends PHPUnit_Framework_TestCase {
protected function setUp() {}
protected function tearDown() {}
public function testToProper() {
$this->assertEquals(
'Sebastian',
toProper( 'sebastian' )
);
}
}
?>
it works fine, I can run it...
but if I select test file from format.php i get
Test file for the selected source file
was not found
any idea?
saludos
sas
ps: another question, is there a way to update generated tests without having to manually delete them???
ps2: using netbeans 2.8 dev
How you've written your Unit test case is 100% correct. The problem lies with common convention and how PHPUnit and Netbeans relies on them.
Best practice these days is to write all your code in an object orientated fashion. So instead of having a PHP file full of utility functions like you have, you wrap these functions into a class and have them as static functions. Here's an example using your code above,
<?php
class Format
{
public static function toUpper($text)
{
return strtoupper($text);
}
public static function toLower($text)
{
return strtolower($text);
}
public static function toProper($text)
{
return self::toUpper(substr($text, 0, 1 )) . self::toLower(substr($text, 1));
}
}
You'd now use your functions like so,
Format::toProper('something');
PHPUnit, and Netbeans, depend on this object orientated philosophy. When you try to automatically generate a PHPUnit test case, PHPUnit looks in your file for a class. It then creates a test case based on this class and it's public API, and calls it ClassNameTest, where ClassName is the name of the class being tested.
Neatbeans also follows this convention and knows that ClassNameTest is a PHPUnit test case for ClassName, so creates a link between the two in the IDE.
So, my advice is to always use classes where you can. If you have utility functions that don't depend on anything and are used globally, make them static ones.
Side note: I'd get rid of your two functions toUpper() and toLower(). There's no need to wrap built in PHP functions when there's no need to. There's also no need to test them as they are thoroughly tested.
Site note 2: There's kind of a built in PHP equivalent to your function toProper() called ucfirst().

Categories