how to test a parent call to a class wrapper - php

I have the following class I would like to cover with some tests:
namespace Nietonfir\RaygunBundle\Services;
use Raygun4php\RaygunClient;
class Client extends RaygunClient implements NietonfirRaygunClient
{
private $defaultTags = null;
protected function mergeTags($tags)
{
if (is_array($this->defaultTags)) {
if (is_array($tags)) {
$tags = array_merge($this->defaultTags, $tags);
} else {
$tags = $this->defaultTags;
}
}
return $tags;
}
public function setDefaultTags(array $tags)
{
if (0 == count($tags)) {
$this->defaultTags = null;
}
$this->defaultTags = $tags;
}
public function setVersion($version)
{
parent::SetVersion($version);
}
public function sendException($exception, $tags = null, $userCustomData = null, $timestamp = null)
{
$tags = $this->mergeTags($tags);
parent::SendException($exception, $tags, $userCustomData, $timestamp);
}
public function sendError($errno, $errstr, $errfile, $errline, $tags = null, $userCustomData = null, $timestamp = null)
{
$tags = $this->mergeTags($tags);
return parent::SendError($errno, $errstr, $errfile, $errline, $tags, $userCustomData, $timestamp);
}
}
In specific I would like to test that sendException calls parent::SendException with the right $tags parameter. The problem of course is mocking the parent in some way, but I think it's hardly impossible. I was thinking of refactoring the class in order to make Client point to an instance of RaygunClient by means of an attribute. That way, it could be testable, but I'm not sure it's a nifty way to do that. After all, what I want is slightly changing the original parent class calls with normalized arguments.
Any piece of suggestion is more than welcome.

I had this as a comment, but it works as an answer and possible solution for you.
You clarified in the comments that the method you want to be called in your test case will send a cURL request. You want to avoid actually sending that request out during your test, since what you are testing is not PHP's cURL library. If your cURL call is within that method you should probably extract it to another class.
You will then be able to mock that class in your test, inject it in to your actual system that you are trying to test, and assert that when that method is called to send the cURL request the parameters in the request match what you should expect in your test case. It shouldn't matter to your test how those parameters show up the way that they do, but I am assuming that they will be different in some detectable ('assertable') way when funnelled through your parent class' method.
Changes to your system down the road that break this functionality (by supplying the wrong parameters to the cURL request) would then be detected.

Related

Multiple API Calls in a Class

I am trying to make multiple API requests and I have to make the request in different functions that are within a class like so:
class exampleClass
{
function callFunction1 () {
// stuff that makes a call
return $json;
}
function printStuffOut() {
$jsonStuff = $this->callFunction1();
$$jsonStuff->{'result'}[0]->{'fieldName'};
}
function printStuffOut2() {
$jsonStuff = $this->callFunction1();
$jsonStuff->{'result'}[0]->{'fieldName'};
}
}
Am I making two separate API calls?
If I am, is there a way to store that API call information say in an array then use that array in all the other functions in my class?
Answer to first question: Yes you are, each time the method is called it executes all its definition again.
Answer to second question: Yes there is, so called member properties. You can read up about them in the PHP manual here: PHP Manual: Properties
You are making two API calls, but you don't have to.
You can put the contents of a call into a member variable in the class with a default value of NULL, and if you want, you can check if that member variable is NULL before making an API call. For example;
class exampleClass
{
private $api_json = NULL;
private function call_api()
{
if(is_null($this->api_json))
{
$json = // result of api call;
$this->api_json = $json;
}
return $this->api_json;
}
public function printStuffOut() {
$jsonStuff = $this->call_api();
$jsonStuff->{'result'}[0]->{'fieldName'};
}
public function printStuffOut2() {
$jsonStuff = $this->call_api();
$jsonStuff->{'result'}[0]->{'fieldName'};
}
}
You can use following class to achieve multiple API simultaneously/instantly/at once.
Click here to get a class.
How to use it?
Step 1: Get object.
//SANI: GET DATA
$obj = new multiapi();
Step 2: Make a multiple GET Requests.
$obj->data = array(YOUR_URL_1,YOUR_URL_2, OUR_URL_3);
$result = $obj->get_process_requests();
print_r($result);
Step 3: Make a multiple HTTP POST Requests.
//SANI: Request with params only
$obj->data[0]['url'] = 'YOUR_URL_ONE';
$obj->data[0]['post'] = array();
$obj->data[0]['post']['param_1'] = 'param_value_1';
$obj->data[0]['post']['param_2'] = 'param_value_2';

getting started with mocking in PHP

How do I get started with mocking a web service in PHP? I'm currently directly querying the web API's in my unit testing class but it takes too long. Someone told me that you should just mock the service. But how do I go about that? I'm currently using PHPUnit.
What I have in mind is to simply save a static result (json or xml file) somewhere in the file system and write a class which reads from that file. Is that how mocking works? Can you point me out to resources which could help me with this. Is PHPUnit enough or do I need other tools? If PHPUnit is enough what part of PHPUnit do I need to check out? Thanks in advance!
You would mock the web service and then test what is returned. The hard coded data you are expecting back is correct, you set the Mock to return it, so then additional methods of your class may continue to work with the results. You may need Dependency Injection as well to help with the testing.
class WebService {
private $svc;
// Constructor Injection, pass the WebService object here
public function __construct($Service = NULL)
{
if(! is_null($Service) )
{
if($Service instanceof WebService)
{
$this->SetIWebService($Service);
}
}
}
function SetWebService(WebService $Service)
{
$this->svc = $Service
}
function DoWeb($Request)
{
$svc = $this->svc;
$Result = $svc->getResult($Request);
if ($Result->success == false)
$Result->Error = $this->GetErrorCode($Result->errorCode);
}
function GetErrorCode($errorCode) {
// do stuff
}
}
Test:
class WebServiceTest extends PHPUnit_Framework_TestCase
{
// Simple test for GetErrorCode to work Properly
public function testGetErrorCode()
{
$TestClass = new WebService();
$this->assertEquals('One', $TestClass->GetErrorCode(1));
$this->assertEquals('Two', $TestClass->GetErrorCode(2));
}
// Could also use dataProvider to send different returnValues, and then check with Asserts.
public function testDoWebSericeCall()
{
// Create a mock for the WebService class,
// only mock the getResult() method.
$MockService = $this->getMock('WebService', array('getResult'));
// Set up the expectation for the getResult() method
$MockService->expects($this->any())
->method('getResult')
->will($this->returnValue(1)); // Change returnValue to your hard coded results
// Create Test Object - Pass our Mock as the service
$TestClass = new WebService($MockService);
// Or
// $TestClass = new WebService();
// $TestClass->SetWebServices($MockService);
// Test DoWeb
$WebString = 'Some String since we did not specify it to the Mock'; // Could be checked with the Mock functions
$this->assertEquals('One', $TestClass->DoWeb($WebString));
}
}
This mock may then be used in the other functions since the return is hard coded, your normal code would process the results and perform what work the code should (Format for display, etc...). This could also then have tests written for it.

How do you mock a virtual binary file so that exec() / system() / passthru() function output can be tested?

I have an interesting problem and have searched the internet, but haven't yet found an answer.
I work for a company that doesn't allow it's workers to utilize OOP, it is kind of ridiculous, but the working experience is valuable.
Consider the following function:
function get_setting_values_from_file( $parameter )
{
exec("/usr/var/binary --options $parameter", $output, $return);
$settings = file( $output[0] );
foreach( $settings as $setting ) {
if( strstr( $setting, "color") ) {
$setting = explode( ":", $setting );
return $setting[1];
}
}
return false;
}
I need to unit test a similar function. I am currently using phpUnit for my tests and the vfsStream libraries to mock the file system, but how do you mock the call to exec("/usr/var/binary --options $parameter", $output, $return) when I'm developing with no access to the actual system? What is the recommend approach for dealing with test cases like this?
All feedback is appreciated.
You could mock exec() by using a function mock library. I made one (php-mock) for you which requires you to use namespaces
namespace foo;
use phpmock\phpunit\PHPMock;
class ExecTest extends \PHPUnit_Framework_TestCase
{
use PHPMock;
public function testExec()
{
$mock = $this->getFunctionMock(__NAMESPACE__, "exec");
$mock->expects($this->once())->willReturnCallback(
function ($command, &$output, &$return_var) {
$this->assertEquals("foo", $command);
$output = "failure";
$return_var = 1;
}
);
exec("foo", $output, $return_var);
$this->assertEquals("failure", $output);
$this->assertEquals(1, $return_var);
}
}
Simply mock this function to return the text that you are trying to get into $settings. You do not need to call the executable, simply create the file or return.
For instance, assuming the function get_setting_values_from_file() returns the settings as an array, you can simply mock the function in your test to return the settings as an array. Create a test stub to mock the object that contains the get_setting_values_from_file() method, and have that mock simply return the same FALSE, 1 or 2 that the test assumed.
$stub = $this->getMock('GetSettingsClass');
$stub->expects($this->any())
->method('get_settings_from_file')
->will($this->returnValue(0));
This is from the PHPUnit manual -> http://phpunit.de/manual/3.8/en/test-doubles.html#test-doubles.stubs
Optionally, you could even bypass the call, and simply test the functions/code that works on the returns by creating the array and passing it to those functions.
Assumed Example in the main code:
...
$settings = get_setting_values_from_file( 'UserType' );
$UserType = get_user_type($settings);
return $UserType;
function get_user_type($settings)
{
if($settings !== FALSE) // Returned from your function if parameter is not found
{
switch($settings)
{
case 1:
return 'User'; // Best to use Constants, but for example here only
break;
case 2:
return 'Admin';
break;
...
}
}
else
{
return FALSE;
}
}
Now, in your test, you can simply
$this->assertFalse(get_user_type(FALSE, 'Ensure not found data is handled properly as FALSE is returned');
$this->assertEqual('User', get_user_type(1), 'Test UserType=1');
$this->assertEqual('Admin', get_user_type(1), 'Test UserType=2');
...
These work as the code does not call the function that had to mock the read from the OS, but does handle all the expected returns by calling the function processing the setting return value. Here, you have simply assumed the return from the function 'get_setting_values_from_file()' without needing the file or any mocks.
This does NOT however test reading from the file, which I would do in another test by using the setUp and tearDown to actual create a file with the values you want (fopen/fwrite) and then call your function and ensure it returns what is expected.
I hope this helps to explain what I was thinking.

Symfony: using getPartial() in a third party library (in $SFROOT/lib folder)

I am using the events system in Symfony 1.3.8.
I am writing logic for the event handlers. As part of my logic, I may need to send email. I therefore need to get the appropriate partial for the email to be sent.
What is the best way to do this?
I have this so far:
class MyEventHandler
{
public static function handleFooEvent(sfEvent $event)
{
// I need to get partial here
// $body = $this->getPartial('somemodule', 'foo', $params);
}
}
I notice that getPartial() is implemented in sfAction like this:
public function getPartial($templateName, $vars = null)
{
$this->getContext()->getConfiguration()->loadHelpers('Partial');
$vars = null !== $vars ? $vars : $this->varHolder->getAll();
return get_partial($templateName, $vars);
}
To load an helper from anywhere in your application, you can use the following:
sfProjectConfiguration::getActive()->loadHelpers("Partial", "Url", "MyHelper");
Then you can get the needed partial just with:
get_partial('somemodule/somepartial', $params)

How do I write unit tests in PHP? [closed]

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 6 years ago.
Improve this question
I've read everywhere about how great they are, but for some reason I can't seem to figure out how exactly I'm supposed to test something. Could someone perhaps post a piece of example code and how they would test it? If it's not too much trouble :)
There is a 3rd "framework", which is by far easier to learn - even easier than SimpleTest, it's called phpt.
A primer can be found here:
http://qa.php.net/write-test.php
Edit: Just saw your request for sample code.
Let's assume you have the following function in a file called lib.php:
<?php
function foo($bar)
{
return $bar;
}
?>
Really simple and straight forward, the parameter you pass in, is returned. So let's look at a test for this function, we'll call the test file foo.phpt:
--TEST--
foo() function - A basic test to see if it works. :)
--FILE--
<?php
include 'lib.php'; // might need to adjust path if not in the same dir
$bar = 'Hello World';
var_dump(foo($bar));
?>
--EXPECT--
string(11) "Hello World"
In a nutshell, we provide the parameter $bar with value "Hello World" and we var_dump() the response of the function call to foo().
To run this test, use: pear run-test path/to/foo.phpt
This requires a working install of PEAR on your system, which is pretty common in most circumstances. If you need to install it, I recommend to install the latest version available. In case you need help to set it up, feel free to ask (but provide OS, etc.).
There are two frameworks you can use for unit testing. Simpletest and PHPUnit, which I prefer. Read the tutorials on how to write and run tests on the homepage of PHPUnit. It is quite easy and well described.
You can make unit testing more effective by changing your coding style to accommodate it.
I recommend browsing the Google Testing Blog, in particular the post on Writing Testable Code.
I rolled my own because i didnt have time to learn someone elses way of doing things, this took about 20 minutes to write up, 10 to adapt it for posting here.
Unittesting is very usefull to me.
this is kinda long but it explains itself and there is an example at the bottom.
/**
* Provides Assertions
**/
class Assert
{
public static function AreEqual( $a, $b )
{
if ( $a != $b )
{
throw new Exception( 'Subjects are not equal.' );
}
}
}
/**
* Provides a loggable entity with information on a test and how it executed
**/
class TestResult
{
protected $_testableInstance = null;
protected $_isSuccess = false;
public function getSuccess()
{
return $this->_isSuccess;
}
protected $_output = '';
public function getOutput()
{
return $_output;
}
public function setOutput( $value )
{
$_output = $value;
}
protected $_test = null;
public function getTest()
{
return $this->_test;
}
public function getName()
{
return $this->_test->getName();
}
public function getComment()
{
return $this->ParseComment( $this->_test->getDocComment() );
}
private function ParseComment( $comment )
{
$lines = explode( "\n", $comment );
for( $i = 0; $i < count( $lines ); $i ++ )
{
$lines[$i] = trim( $lines[ $i ] );
}
return implode( "\n", $lines );
}
protected $_exception = null;
public function getException()
{
return $this->_exception;
}
static public function CreateFailure( Testable $object, ReflectionMethod $test, Exception $exception )
{
$result = new self();
$result->_isSuccess = false;
$result->testableInstance = $object;
$result->_test = $test;
$result->_exception = $exception;
return $result;
}
static public function CreateSuccess( Testable $object, ReflectionMethod $test )
{
$result = new self();
$result->_isSuccess = true;
$result->testableInstance = $object;
$result->_test = $test;
return $result;
}
}
/**
* Provides a base class to derive tests from
**/
abstract class Testable
{
protected $test_log = array();
/**
* Logs the result of a test. keeps track of results for later inspection, Overridable to log elsewhere.
**/
protected function Log( TestResult $result )
{
$this->test_log[] = $result;
printf( "Test: %s was a %s %s\n"
,$result->getName()
,$result->getSuccess() ? 'success' : 'failure'
,$result->getSuccess() ? '' : sprintf( "\n%s (lines:%d-%d; file:%s)"
,$result->getComment()
,$result->getTest()->getStartLine()
,$result->getTest()->getEndLine()
,$result->getTest()->getFileName()
)
);
}
final public function RunTests()
{
$class = new ReflectionClass( $this );
foreach( $class->GetMethods() as $method )
{
$methodname = $method->getName();
if ( strlen( $methodname ) > 4 && substr( $methodname, 0, 4 ) == 'Test' )
{
ob_start();
try
{
$this->$methodname();
$result = TestResult::CreateSuccess( $this, $method );
}
catch( Exception $ex )
{
$result = TestResult::CreateFailure( $this, $method, $ex );
}
$output = ob_get_clean();
$result->setOutput( $output );
$this->Log( $result );
}
}
}
}
/**
* a simple Test suite with two tests
**/
class MyTest extends Testable
{
/**
* This test is designed to fail
**/
public function TestOne()
{
Assert::AreEqual( 1, 2 );
}
/**
* This test is designed to succeed
**/
public function TestTwo()
{
Assert::AreEqual( 1, 1 );
}
}
// this is how to use it.
$test = new MyTest();
$test->RunTests();
This outputs:
Test: TestOne was a failure
/**
* This test is designed to fail
**/ (lines:149-152; file:/Users/kris/Desktop/Testable.php)
Test: TestTwo was a success
Get PHPUnit. It is very easy to use.
Then start with very simple assertions. You can do alot with AssertEquals before you get into anything else. That's a good way to get your feet wet.
You may also want to try writing your test first (since you gave your question the TDD tag) and then write your code. If you haven't done this before it is an eye-opener.
require_once 'ClassYouWantToTest';
require_once 'PHPUnit...blah,blah,whatever';
class ClassYouWantToTest extends PHPUnit...blah,blah,whatever
{
private $ClassYouWantToTest;
protected function setUp ()
{
parent::setUp();
$this->ClassYouWantToTest = new ClassYouWantToTest(/* parameters */);
}
protected function tearDown ()
{
$this->ClassYouWantToTest = null;
parent::tearDown();
}
public function __construct ()
{
// not really needed
}
/**
* Tests ClassYouWantToTest->methodFoo()
*/
public function testMethodFoo ()
{
$this->assertEquals(
$this->ClassYouWantToTest->methodFoo('putValueOfParamHere), 'expectedOutputHere);
/**
* Tests ClassYouWantToTest->methodBar()
*/
public function testMethodFoo ()
{
$this->assertEquals(
$this->ClassYouWantToTest->methodBar('putValueOfParamHere), 'expectedOutputHere);
}
For simple tests AND documentation, php-doctest is quite nice and it's a really easy way to get started since you don't have to open a separate file. Imagine the function below:
/**
* Sums 2 numbers
* <code>
* //doctest: add
* echo add(5,2);
* //expects:
* 7
* </code>
*/
function add($a,$b){
return $a + $b;
}
If you now run this file through phpdt (command-line runner of php-doctest) 1 test will be run. The doctest is contained inside the < code > block. Doctest originated in python and is fine for giving useful & runnable examples on how the code is supposed to work. You can't use it exclusively because the code itself would litter up with test cases but I've found that it's useful alongside a more formal tdd library - i use phpunit.
This 1st answer here sums it up nicely (it's not unit vs doctest ).
phpunit is pretty much the defacto unit testing framework for php. there is also DocTest (available as a PEAR package) and a few others.
php itself is tested for regressions and the like via phpt tests which can also be run via pear.
Codeception tests are much like common unit tests but are much powerful in things where you need mocking and stubbing.
Here is the sample controller test. Notice how easily stubs are created. How easily you check the method was invoked.
<?php
use Codeception\Util\Stub as Stub;
const VALID_USER_ID = 1;
const INVALID_USER_ID = 0;
class UserControllerCest {
public $class = 'UserController';
public function show(CodeGuy $I) {
// prepare environment
$I->haveFakeClass($controller = Stub::makeEmptyExcept($this->class, 'show'));
$I->haveFakeClass($db = Stub::make('DbConnector', array('find' => function($id) { return $id == VALID_USER_ID ? new User() : null ))); };
$I->setProperty($controller, 'db', $db);
$I->executeTestedMethodOn($controller, VALID_USER_ID)
->seeResultEquals(true)
->seeMethodInvoked($controller, 'render');
$I->expect('it will render 404 page for non existent user')
->executeTestedMethodOn($controller, INVALID_USER_ID)
->seeResultNotEquals(true)
->seeMethodInvoked($controller, 'render404','User not found')
->seeMethodNotInvoked($controller, 'render');
}
}
Also there are other cool things. You can test database state, filesystem, etc.
Besides the excellent suggestions about test frameworks already given, are you building your application with one of the PHP web frameworks that has automated testing built in, such as Symfony or CakePHP? Sometimes having a place to just drop in your test methods reduces the start-up friction some people associate with automated testing and TDD.
Way too much to re-post here, but here is a great article on using phpt. It covers a number of aspects around phpt that are often overlooked, so it could be worth a read to expand your knowledge of php beyond just writing a test. Fortunately the article also discusses writing tests!
The main points of discussion
Discover how marginally documented aspects of PHP work (or pretty much any part for that matter)
Write simple unit tests for your own PHP code
Write tests as part of an extension or to convey a potential bug to the internals or QA groups
I know there is a lot of info here already, but since this still shows up on Google searches i might as well add Chinook Test Suite to the list. It is a simple and small test framework.
You can easily test your classes with it and also create mock objects. You run the tests through a web browser and (not yet) through a console.
In the browser you can specify what test class or even what test method to run. Or you can simply run all tests.
A screenshot from the github page:
What i like about it is the way you assert tests. This is done with so called "fluent assertions". Example:
$this->Assert($datetime)->Should()->BeAfter($someDatetime);
And creating mock objects is a breeze too (with a fluent like syntax):
$mock = new CFMock::Create(new DummyClass());
$mock->ACallTo('SomeMethod')->Returns('some value');
Anyway, more info can be found on the github page with a code example as well:
https://github.com/w00/Chinook-TestSuite

Categories