PHPT avoid constructor and target functions directly - php

I have the following class:
class Validator {
public function __construct($file){
$errors = $this->errors($file_array[CSV]['errors']);
}
public function errors_func($errors){
if($errors != 0){
throw new Exception('Error Uploading');
}
}
}
I'm attempting to target the errors_func() function directly through my test script without the need to first invoke the constructor. The PHPT test script can be seen below:
--TEST--
check_mime() function - A basic test to see if check mime works. :)
--FILE--
<?php
require_once('my/path');
$valid = new Validation;
$re = $valid->errors_func('1);
var_dump($re);
?>
--EXPECT--
bool(true)
As you would expect though the test script fails becuase a parameter is expected when the object of the class is created. Is there a way to create an object of the Validation class without needing to pass an argument to the class __constructer?

I've found a solution to this by using ReflectionClass. The new test script would look like this:
--TEST--
check_mime() function - A basic test to see if check mime works. :)
--FILE--
<?php
require_once('my/path');
$valid = new ReflectionClass('Validator');
$valid_direct = $valid->newInstanceWithoutConstructor();
$re = $valid_direct->errors_func('1);
var_dump($re);
?>
--EXPECT--
bool(true)

Related

creating multiple instances of splFileObject

I have a class similar to this
class x {
function __construct($file){
$this->readData = new splFileObject($file);
}
function a (){
//do something with $this->readData;
}
function b(){
//do something with $this->readData;
}
}
$o = new x('example.txt');
echo $o->a(); //this works
echo $o->b(); //this does not work.
it seems if which ever method called first only works, if they are called together only the first method that is called will work. I think the problem is tied to my lack of understand how the new object gets constructed.
The construct is loaded into the instance of the class. And you're instantiating it only once. And accessing twice. Are different actions. If you want to read the file is always taken, should create a method that reads this file, and within all other trigger this method.
I tested your code and it worked normal. I believe it should look at the logs and see if any error appears. If the file does not exist your code will stop.
Find for this error in your apache logs:
PHP Fatal error: Uncaught exception 'RuntimeException' with message 'SplFileObject::__construct(example.txt): failed to open stream
Answering your comment, this can be a way:
<?php
class x {
private $defaultFile = "example.txt";
private function readDefaultFile(){
$file = $this->defaultFile;
return new splFileObject($file);
}
function a (){
$content = $this->readDefaultFile();
return $content ;
}
function b(){
$content = $this->readDefaultFile();
return $content ;
}
}
$o = new x();
echo $o->a();
echo $o->b();
Both methods will return an object splFile.

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.

Run a PHPUnit Selenium test case programatically ("within PHP")

How can I run a test "within PHP" instead of using the 'phpunit' command? Example:
<?php
require_once 'PHPUnit/Extensions/SeleniumTestCase.php';
class MySeleniumTest extends PHPUnit_Extensions_SeleniumTestCase {
protected function setUp() {
$this->setBrowser("*firefox");
$this->setBrowserUrl("http://example.com/");
}
public function testMyTestCase() {
$this->open("/");
$this->click("//a[#href='/contact/']");
}
}
$test = new MySeleniumTest();
//I want to run the test and get information about the results so I can store them in the database, send an email etc.
?>
Or do I have to write the test to a file, invoke phpunit via system()/exec() and parse the output? :(
Just use the Driver that's included.
require_once 'PHPUnit/Extensions/SeleniumTestCase/Driver.php';
//You may need to load a few other libraries. Try it.
Then you need to set it up like SeleniumTestCase does:
$driver = new PHPUnit_Extensions_SeleniumTestCase_Driver;
$driver->setName($browser['name']);
$driver->setBrowser($browser['browser']);
$driver->setHost($browser['host']);
$driver->setPort($browser['port']);
$driver->setTimeout($browser['timeout']);
$driver->setHttpTimeout($browser['httpTimeout']);
Then just:
$driver->open('/');
$driver->click("//a[#href='/contact/']");
Here's an example from the phpunit docs:
<?php
require_once 'PHPUnit/Framework.php';
require_once 'ArrayTest.php';
require_once 'SimpleTestListener.php';
// Create a test suite that contains the tests
// from the ArrayTest class.
$suite = new PHPUnit_Framework_TestSuite('ArrayTest');
// Create a test result and attach a SimpleTestListener
// object as an observer to it.
$result = new PHPUnit_Framework_TestResult;
$result->addListener(new SimpleTestListener);
// Run the tests.
$suite->run($result);
?>
The code for SimpleTestListener is on the same page.

how do I override php://input when doing unit tests

I'm trying to write a unit test for a controller using Zend and PHPUnit
In the code I get data from php://input
$req = new Zend_Controller_Request_Http();
$data = $req->getRawBody();
My code works fine when I test the real application, but unless I can supply data as a raw http post, $data will always be blank. The getRawBody() method basically calls file_get_contents('php://input'), but how do I override this in order to supply the test data to my application.
I had the same problem and the way I fixed it was to have the 'php://input' string as a variable that is settable at run time. I know this does not really apply directly to this question as it would require modifying the Zend Framework. But all the same it may be helpful to someone.
For example:
<?php
class Foo {
public function read() {
return file_get_contents('php://input');
}
}
would become
<?php
class Foo {
public $_fileIn = 'php://input';
public function read() {
return file_get_contents($this->_fileIn);
}
}
Then in my unit test I can do:
<?php
$obj = new Foo();
$obj->_fileIn = 'my_input_data.dat';
assertTrue('foo=bar', $obj->read());
You could try mocking the object in your unit tests. Something like this:
$req = $this->getMock('Zend_Controller_Request_Http', array('getRawBody'));
$req->method('getRawBody')
->will($this->returnValue('raw_post_data_to_return'));
Provided the $req->getRawBody() is, as you say, the same as file_get_contents('php://input')...
$test = true; /* Set to TRUE when using Unit Tests */
$req = new Zend_Controller_Request_Http();
if( $test )
$data = file_get_contents( 'testfile.txt' );
else
$data = $req->getRawBody();
Not a perfect solution, but similar to what I have used in the past when designing scripts to handle piped emails with great success.
Zend_Controller_Request_HttpTestCase contains methods for setting and getting various http request/responses.
For example:
$req = new Zend_Controller_Request_HttpTestCase;
$req->setCookie('cookie', 'TRUE');
$test = $this->controller->cookieAction($req);
$this->assertSame($test, TRUE);

Categories