I'm currently testing a wrapper to an API with PHPUnit (CLI).
Due to the nature of the tests, I can pretty much use the same code for testing two different use cases. The only difference is in the values I send to the API as parameters.
So, I decided to write a class DefaultTest, where I test the API using default values used by the API and a second CustomTest(Case) where I test my parameter container with differing values. CustomTest inherites from DefaultTest, as all the functions used for validating the returned data are equivalent in both cases.
Here's some code for your understanding:
class DefaultTest extends PHPUnit_Framework_TestCase {
public function testAPIMethod()
{
$this->checkParameterContainer();
$this->validateResults();
}
public function checkParameterContainer()
{
/* Set up default parameter container */
}
public function validateResults()
{
/* Validate the results */
}
}
class CustomTest extends DefaultTest {
public function checkParameterContainer()
{
/* Set up custom parameter container */
}
public function validateResults()
{
parent::validateResult();
}
}
PHPUnit takes the child class, executes the testAPIMethod, leading to CustomTest::checkParameterContainer() and DefaultTest::validateResults() being executed.
But DefaultTest's testAPIMethod is never executed, as DefaultTest::checkParameterContainer() is never called.
Both classes are fully valid TestCases and DefaultTest is executed normally when not specialized.
So, my question for you guys: Why is that? Do I miss something here? Is this by design?
In case, somebody needs it: PHPUnit uses reflection to find test methods on each class, but will not search in parent classes. So the following will be needed in the child test class:
public function testAPIMethod()
{
parent::testAPIMethod();
}
Related
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.
I'm not sure if it's the proper place for such question since it's rather theoretical than the specific code sample but I'll ask anyway.
So, at some point PHP introduced type constrains in function definition (except basic types of course), i.e.
class A {
public $value;
}
function foo($someInt, A $a) {...}
What make me wondering is if PHPUnit mocks can be used in such situation:
class functionTest extends PHPUnit_Framework_TestCase {
public function testFoo() {
$mockA = $this->getMockBuilder('A')->getMock();
$this->assertEquals('some result', foo(1, $mockA));
}
}
Would such call be accepted when the test runs (ofc. I skipped includes and stuff to keep it simple).
And the more interesting question: if yes, then how is it implemented?
Yes it will be working, PHPUnit will mock your object. This mocked object will dynamically extends the base Object you want to mock.
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.
I am a beginner of unit testing and having difficulty of testing an algorithm (which is executable by cron in actual implementation) that is within a PHP class with functions that don't have arguments as well as depending on other classes for data sources, e.g. this one:
class Mailing_System_Algo {
function __construct()
{
//Run the mailing system method
$this->execute_mailing_system();
}
function execute_mailing_system()
{
$Class_Data_Source = new Data_Source;
$groups = $Class_Data_Source->get_groups();
//Proceed only if groups are defined
if (!(empty($groups))) {
//rest of the algo codes here-very long and lots of loops and if statements
}
}
}
I would like treat the algo function like a blackbox so I won't be altering anything on their codes when I do the test. But how can I start testing them by feeding them inputs if the execute_mailing_system will run right away the moment the class is instantiated?
Supposing I would like to check if the algo will execute with or without groups, how can I provide an input in my unit test codes for $groups?
This is how my test case would look like:
class WP_Test_Mailing_System_Algo extends WP_UnitTestCase {
/**
* Run a simple test to ensure that the tests are running
*/
function test_tests() {
//no problem here
$this->assertTrue( true );
}
function test_if_algo_wont_run_if_no_groups_provided {
//Instantiate, but won't this algo run the construct function rightaway?
$Mailing_System_Algo = new Mailing_System_Algo;
//rest of the test codes here
//how can I access or do detailed testing of execute_mailing_system() function and test if it won't run if groups are null or empty.
//The function does not have any arguments
}
}
Of course there are lots of tests that I would be writing but I'm currently stuck on this one. This is the first test that I would need to execute. But I have a problem on how to get started doing this. I believe that once I get the technique right, the rest of the tests would be straightforward. I would appreciate any of your inputs and help..Thanks.
There is two flaws with the code that will hamper testing:
Constructor does Real Work
Hard-Coded Dependencies
You can improve this by changing the class to
class Mailing_System_Algo
{
public function __construct()
{
// constructors should not do work
}
public function execute_mailing_system(Data_Source $Class_Data_Source)
{
$groups = $Class_Data_Source->get_groups();
//Proceed only if groups are defined
if (!(empty($groups))) {
//rest of the algo codes here-very long and lots of loops and if statements
}
}
}
This is way, you can replace your Data_Source with a Mock or Stub, returning defined test values.
If this is not an option, have a look at the Test Helper extension:
https://github.com/sebastianbergmann/php-test-helpers¹
In particular, have a look at set_new_overload(), which can be used to register a callback that is automatically invoked when the new operator is executed.
¹ the Test-Helper extension is superseded by https://github.com/krakjoe/uopz
This is the basic class design
class CustomModule {
public __construct() { }
//Run me first automaticly
public function exec($str) { }
}
class Randomizer extends CustomModule {
public __construct() { }
//Call me
public function exec($str) { }
}
As I am designing a plugin/module system for extern developers I need the CustomModule->exec() to run first, I do not want to leave it up to the devs to have to call base->exec($str).
I want CustomModule::exec() called automaticly before Randomizer::exec() is called without having to put code in Randomizer::exec(). Is This Possible perhaps with magic function?
In my opinion, i would use this way:
Instead of calling _construct in exec of Randomizer, you can define a constructor in Randomizer and call parent::_construct
class CustomModule {
//Run me first automaticly
public function exec($str) { }
public __construct($str) {
$this->exec($str);
}
}
class Randomizer extends CustomModule {
//Call me
public function exec($str) {
parent::__construct($str);
}
}
If your object requires some initialization before you can "release* it into the rest of application, then it means that you need a factory for this. This is how you should be solving it, if you require to call some method only once.
If such execution happens each time you call exec() method, then instead you should be using some sort of containment (in a form of decorator or just you standard composition of objects).
Basically, you need to restructure your code.
After a bit more thought I realized this is BAD design. I have to keep the code base simple and scaleable and this would only make a mess in large projects.
As the only program calling the Randomizer::exec() is my inhouse built program I can just call CustomModule::exec() on the previous line and get a boolean response to see if it should continue to the next line.
Sorry to have to end this Q' short