How to document PHPUnit tests - php

I'm writing a lot of unit tests and I'm afraid one day I'll come back to read the test codes and not be able to understand what's being tested.
The question is: How do i document PHPUnit tests using PHPDoc?

Use the #covers annotation (it's specific to PHPUnit, not a documentation tag used by phpDocumentor) to highlight what the test case is supposed to exercise. By having it in the docblock, you tell the code reader what code is targeted by the test. If you have phpDocumentor also generating docs for your test cases, then it should treat the annotation as a "custom tag", and show it as generic information. Note, though, that the point of #covers is to limit the code coverage measurements done by PHPUnit. Its use as doc info is incidental, but useful.
If you want some kind of document linking between the test case and the tested code, also put the #uses tag in the test case's docblock. That should result in #used-by tag automatically appearing in the documentation for the tested method/function.

One way as suggested is to use the test function name but this can end up too abbreviated and cryptic. In this case put some text in the optional $message parameter to explain what the test is doing.
assertSame(mixed $expected, mixed $actual[, string $message = ''])
I finds this helps, particularly if you are used to writing JavaScript tests with something like Jasmine where you put a human readable sentence to explain what is being tested for each test.
Here is a simple example. If you put the test description as the default value for a function argument it will be documented. If you put just one test per function (i.e. single responsibility principle) then when you look back in a few years time maybe the tests will make more sense than having multiple tests per function.
<?php
use PHPUnit\Framework\TestCase;
final class ArrayPushTest extends TestCase
{
public function testPushStringToEmptyArray(string $description =
'A string is pushed into an empty array at array index 0.'
) : void
{
$a = [];
array_push($a, 'zero');
$this->assertSame('zero', $a[0], $description);
}
}
And this is what it looks like in the docs with phpDocumentor:
phpDocumentor output

Related

In phpDoc, is it neccessary to define parameter type?

an old fashioned example:
/**
* #param string $a - test parameter
*/
public function test($a)
{
}
but now that Php has types, I would write:
/**
* #param $a - test parameter
*/
public function test(string $a)
{
}
since it has a parameter, so adding "string" to phpdoc is verbose.
"Necessary" depends on what you're using to parse the annotation (if anything)*
If this is PHPDocumentor itself, you'll want to stick with the standard that it prescribes. Even if it works without the type now, there's no guarantee that a future version will, and as mentioned in Alex Howansky's answer, the type is currently defined as mandatory. From their manual:
With the #param tag it is possible to document the type and function of a single argument of a function or method. When provided it MUST contain a Type to indicate what is expected; the description on the other hand is OPTIONAL yet RECOMMENDED in case of complicated structures, such as associative arrays.
PHPStorm (at least the version I have in front of me) acts a bit strangely if you leave out the type-hint in a parameter. If I use
* #param $a Some useful comment about my parameter
then I get a warning about Undefined class Some. Apparently it's taking the first word other than the #param annotation and the variable name, and assuming that's the type. I can't find a reference to this behaviour in the phpdoc manual (providing the type after the variable), so that could itself be non-standard. Interestingly, if the first character after the variable name is a hyphen (as in the example in your question), then the warning is supressed.
I've seen a lot of code recently that leaves out the annotations entirely, and relies on the language's internal type-hinting (both parameter and return) to do the job. This is perfect, as long as you don't need to add a description to any of them. PHPStorm will warn you about missing parameter annotations the moment you provide any (but not all) of them, which means if you want to provide a comment for one then you'll need to add the rest, commented or not.
You mention verbosity in your question, and if all you're concerned about is human readability then by all means leave out the type. Phpdoc itself has a standard, but you're absolutely not bound by it. It's your code, ultimately. But if you're shipping a package that other developers might use, or if any of your toolchain (from IDE, through static analysis, to documentation generation itself) aren't happy with the non-standard usage, then you'll have to weigh up the decision again. Either way it comes down to whether you're the only one (person or machine) reading your code; if you're not, then stick with the standards, even if it means typing a few extra characters.
--
* This can include things that actually do affect the way the code runs - PHP allows you to fetch these annotations with the getDocComment methods in the Reflection API. Use-cases for this tend not to include #param annotations (more often it'll be something package specific like Doctrine's ORM annotations), which are almost exclusively used for documentation, but I don't want to over-generalise and say that this can't have an effect on your code's actual functionality.
The phpDocumentor docs state that the Datatype field is required for #param. Those docs are quite old, but I would expect apps which consume tags to still abide by that requirement. Lately, I've tended to skip the #param tag completely when I have an explicit typehint present.
PHPCS will alert if you leave it out but have a typehint, like in your example:
/**
* #param $arg The arg.
*/
public function foo(int $arg) {
PHPStan will alert if you have a #param tag type and a typehint that don't match, like this:
/**
* #param string $arg The arg.
*/
public function foo(int $arg) {

Remove method by name from php class (not in runtime)

Situation
I have a file which contains 2-3 classes. Each class may and may not contain a destructor function __destruct().
I am retrieving these classes using composer and have no real control over it, neither I can selectively say 'go on and ignore lines X~Z' where the destructor calls are located, as these lines may slightly change.
I need to get rid of all the destructors - or at least prevent them from executing on object destruction, as other part of code which I have no control over jumps into endless destruct loop.
Approaches I tried and considered:
Regex
My initial thought was to write a regex, that would match all these functions and removed them (best effort regex, I am sure there would be corner cases for which the regex would not work), but eventually, after remembering various questions about using regexes inappropriately, I reconsidered - not mentioning the fact, that coming up with working regex seems to be a problem for me as well.
Curly brackets block used for nested scope in C
I have some background in C, so for a second I thought I could just match all the lines with function __destruct(), verify there is no { on the same line and comment the definition out, so I would get something like this:
# function __destruct()
{
echo "initiating destructor function";
$this->callToSomething();
}
Which I thought would not execute (or at very least - would not execute on object destruction, which is why I need to comment this out). But PHP does not allow this syntax and I can not do that. Maybe it allows for some other syntax which would achieve the same results?
Parsing, Reflection? ...?
I do not really want to write myself a PHP parser of its own for this task, but if that is what it will take, I will do it. But since there is already a Reflection class in PHP, maybe there would be a way to load class into the memory, remove the destructors in runtime and then overwrite class definition on disk?
I do not see why you cannot use a regex here. Sure, you need a more advanced pattern.
But you should be never forced to touch it.
Here is a pattern that finds __destruct() blocks:
function\s+__destruct\s*\(\s*\)\s*({(?>[^{}\\]++|\\.|(?1))*+})
Demo
All you need to do is to load the files in question, run
$re = '/function\s+__destruct\s*\(\s*\)\s*({(?>[^{}\\\\]++|\\\\.|(?1))*+})/s';
$result = preg_replace($re, '', $str);
And save the files back to disk. C'est ça.

Do I have to unit test every value a parameter could take?

For example, if I have a method that execute simple logic and take an int parameter in input, do I have to unit test cases when input is :
a good int (like 1)
a bad int (like 822873873824676372732367232637233)
a descent float
a bad float
a bool
a string
no parameter
Well I think I already know the answer, but where is the limit?
Also, when the method have A and B parameters, do I have to test every cases that could happens by doing these methods? :
testGoodAWithoutB
testGoodBWithoutA
testGoodAWithGoodB
testBadAWithoutB
testGoodAWithBadB
...
The answer to your question is: no, of course not.
It makes no sense to test every possible value. If you are working with unit tests I guess that you are trying to ceap your code as clean as possible. For this your function should follow the single responsibility principle.
If your function just hase one functionality it makes it easy just to test that.
It depends also what your function can expect. When you have a function add(a, b) it depends on the context inside your programms. When the error handling is done before the function call and you are sure that you will always get valid values there is no need to test this, because your function is not responsible for that. If the same function is for example a public method the function has to check the input values. In that case you should also test that.
You need to keep in mind that your tests has to be readeable for humans. If you are testing everything which could happen the next 100 years the tests will be not so easy to understand.
Your tests should also be something like a documentation for other programmers. So just test your function like your function should be called.

Many test cases to cover a function - phpunit

For the following function I need to write more test cases, I have already written one, can someone give some ideas, Perhaps to test return values of intermediate function calls.
public function calculateShortestPath($graphObj, $start, $destination)
{
$shortestPath = null;
if ($this->validateParams($graphObj, $start, $destination) == true) {
$result = $this->getAllVerticesAndNeighbours($graphObj);
$vertices = $result[self::VERTICES];
$neighbours = $result[self::NEIGHBOURS];
$vertexCost = array_fill_keys($vertices, self::INFINITY);
$visitedVertices = array_fill_keys($vertices, null);
$vertexCost[$start] = 0;
$vertexQueue = $vertices;
$result = $this->getShortestPath($vertexQueue, $vertexCost, $neighbours, $visitedVertices, $destination);
$vertexCost = $result[self::VERTEX_COST];
$shortestPathVertices = $result[self::SHORTEST_PATH_VERTICES];
$path = $this->getRefinedShortestPath($shortestPathVertices, $destination);
$shortestPath = new ShortestPath($path, $vertexCost[$destination]);
}
return $shortestPath;
}
I have written following case already,
/**
* Test for calculateShortestPath function
*
* #param string|int $start starting point
* #param string|int $destination destination point
* #param array $expectedShortestPath expected shortest path
* #param int|float $expectedCost expected cost
* #dataProvider testCalculateShortestPathDataProvider
*/
public function testCalculateShortestPath($start, $destination, $expectedShortestPath, $expectedCost)
{
$actualResult = $this->shortestPathCalc->calculateShortestPath($this->graph, $start, $destination);
/* #var $actualResult ShortestPath */
$this->assertEquals(
$expectedShortestPath,
$actualResult->getPath(),
sprintf('Incorrect shortest path from %d to %d !', $start, $destination)
);
$this->assertEquals(
$expectedCost,
$actualResult->getCost(),
sprintf('Incorrect shortest path cost from %d to %d !', $start, $destination)
);
}
As a general rule, unit tests should exhibit two traits:
Each test should test one and only one thing
Each test should be as dumb as humanly possible
The reason for the first trait is that if a test fails it will log which test case method triggered the failure. If that method tests lots of things it makes it more of a nuisance to determine the exact failure.
The second trait exists because every time a test fails, then there must be a problem. The problem can only exist in one of two places (ignoring bugs in PHP and its extensions, or in the unit tester): in the code under test, or in the test itself. "Clever" tests will make it difficult to determine which case it is, and you don't want to spend an hour or two hunting down a bug in your class when it turns out it's actually the test that's buggy.
In your example above your current test is pretty good, but it breaks the first rule (there's two tests happening at once). Unless running the method under test is really expensive it might be worth having this test case twice, with the first run asserting the expected shortest path and the second one asserting the expected cost (and if your method does have an expensive run time then there's an incentive to try and optimise it right there :) ).
Your test may also break the second rule because I have no idea what $this -> graph is or how it's set up. Is this an actual business object or just a mockup of it? You might want to look into the mocking an stubbing capabilities of PHPUnit.
Regarding test strategies, there are two general approaches - Black box testing (where you test a unit against its specifications but treat it like you have no knowledge of its internal workings) and glass box (where you use your knowledge of the unit's internal workings to devise tests). My preferred approach it to mainly adopt a black box strategy, build tests around the specs, and then once I've got the spec fully covered move to a glass box strategy to write additional tests that will cover any code paths that the black box test doesn't exercise.
Testing is often about boundaries, as in testing responses to input when that input is both valid and invalid. So for each method your class has, you want one typical case (what's often called the "happy path") that demonstrates typical usage, a number of extreme but still valid inputs, a range of inputs that are just outside the valid range (if your method excepts numbers in the range 1-10 then a test case with 0 and a test case with 11 would cover those cases) and a test case with data wildly outside of the valid range. Many errors in programming occur at the transition between valid and invalid input (the off-by-one error is probably the most notorious example) so your tests should cover those regions thoroughly.
One nice thing about black box testing is that if you know the specs, you can write the tests before there's any code to even test. Then you can start implementing code, test it, correct it for failed tests and repeat this process until you get a 100% pass rate. This is called Test Driven Development.

Structuring Decorators in PHP

I'm sort of a novice developer trying to expand my toolbox and learn some more tricks. I recently came across a pattern in Python called "decoration" and I was wondering if/how I could implement this in PHP as I have an existing PHP code base.
Here is a short example of what I mean:
import time
def log_calls(func):
def wrapper(*args, **kwargs):
now = time.time()
print("Calling {0} with {1} and {2}".format(
func.__name__,
args,
kwargs
))
return_value = func(*args, **kwargs)
print("Executed {0} in {1}ms".format(
func.__name__,
time.time() - now
))
return return_value
return wrapper
#log_calls
def test1(a,b,c):
print("\ttest1 called")
#log_calls
def test2(a,b):
print("\ttest2 called")
#log_calls
def test3(a,b):
print("\ttest3 called")
time.sleep(1)
test1(1,2,3)
test2(4,b=5)
test3(6,7)
It doesn't necessarily have to be that syntactically pretty; I understand that all languages have their nuances and I know PHP does not support that syntax. But I still want to be able to achieve the same effect while rewriting as little code as possible.
Basically no, it's not supported in PHP in any way at all. As far as I know, it's not even on the roadmap for future PHP versions.
Of interest, and slightly relevant: The closest I could think of in PHP-land to what you're after is if you use phpUnit to test your code. phpUnit implements something along these lines for its own use, using references in docblock type comments above a method. eg:
/**
* #dataProvider myProviderFunc
*/
public function myTestFunc($argsFromProvider) {
....
}
public function myProviderFunc() {
return array(....);
}
Thus, when phpUnit wants to call myTestFunc(), it first calls myProviderFunc(), and passes the output of that function into myTestFunc().
This strikes me as being close to, but not quite the same as the decorator syntax you're describing. However, it's not standard PHP syntax; phpUnit implements all of this stuff itself. It reads the source code and does a load of pre-processing on as it parses the comment blocks before running the tests, so it's not exactly efficient. Suitable for a unit testing tool, but not for a production system.
But no, the short answer to your question is that what you want can't be done in PHP. Sorry.
PHP has no syntactic support for the decorator pattern, but nothing really hinders you from implementing it yourself.
You can look into the following discussions, which might be relevant to your question:
how to implement a decorator in PHP?
Trying to implement (understand) the Decorator pattern in php
Here is another resource, with UML diagrams and code samples in multiple languages, including PHP.
Decorator Design Pattern

Categories