How to indicate that a PHPUnit test is expected to fail? - php

Is it possible to mark a test as "expected to fail" with PHPUnit? This would be useful when performing TDD, and you want to distinguish between genuinely failed tests, and tests that happen to fail because the associated code hasn't been written yet.

I think in these cases, it's fairly standard to simply mark the test as skipped. Your tests will still run and the suite will pass, but the test runner will alert you of the skipped tests.
http://phpunit.de/manual/current/en/incomplete-and-skipped-tests.html

The 'correct' method of handling this is to use $this->markTestIncomplete(). This will mark the test as incomplete. It will come back as passed, but it will display the message provided. See http://www.phpunit.de/manual/3.0/en/incomplete-and-skipped-tests.html for more information.

I really think it's a bad practice, however you can trick PHPUnit this way:
/**
* This test will succeed !!!
* #expectedException PHPUnit_Framework_ExpectationFailedException
*/
public function testSucceed()
{
$this->assertTrue(false);
}
More cleanly:
public function testFailingTest() {
try {
$this->assertTrue(false);
} catch (PHPUnit_Framework_ExpectationFailedException $ex) {
// As expected the assertion failed, silently return
return;
}
// The assertion did not fail, make the test fail
$this->fail('This test did not fail as expected');
}

The comment by sixty-nine above is nearly perfect for what I was searching for.
The fail() method is useful for when you set a test for an expected exception and if it did not trigger the exception you want the test to fail.
$this->object->triggerException();
$this->fail('The above statement was expected to trigger and exception.');
Of course the triggerException is replaced by something in your object.

If you want to have a test fail but know that its failure was expected, you can add a message to the assertion that will output in the results:
public function testExpectedToFail()
{
$this->assertTrue(FALSE, 'I knew this would happen!');
}
In the results:
There was 1 failure:
1) testExpectedToFail(ClassTest)
I knew this would happen!

In PHPUnit 8.2.5 you can simply expect the thrown assertion exception:
$this->expectException('PHPUnit\Framework\ExpectationFailedException');
$this->assertTrue(false);

Related

How to simulate and properly write test with error_get_last() function in phpunit

So the question is the same as in subject:
How to simulate and properly write test with error_get_last() function in phpunit
Sample code to write test to:
$lasterror = error_get_last();
if ($lasterror !== null) {
//do something
}
Thanks for asking this question, it was not clear to me at the very beginning where the problem resulted from writing a test for it. That is due to the nature of error and exception handling, especially in testing these things can be considered a bit harder and there are normally no ready-made "easy" solutions because at the end of the day you need to write the test yourself.
I hope this could be clarified in comments and the following can show how to approach them in a way.
NOTE: As we're writing test-code, I use assert() statements in the examples, and this is by intention as assert is a more pure language feature. It makes the examples more portable, too.
To make use of it, execute php having assertions in development mode and throwning (zend.assertions=1 and assert.exception=1) and run the example as it evolves and have later phpunit run with these settings as well.
You can certainly port this into a concrete test-case to implement it Phpunit specific, for the examples the concrete assertion library should not be of interest, but the assertions. They are expected in the examples to bring PHP to halt if they aren't fullfilled and this is how I wrote the examples (some people say those are expectations).
In general testing code that tests for the side-effect of there being an error:
$lasterror = error_get_last();
if ($lasterror !== null) {
//do something
}
and then in your test-suite you get not errors but exceptions:
#trigger_error('Oh no'); // ErrorException: Oh no
which will prevent further code to run (the code you want to put under test).
What to do now? Well, the naked error-trigger would make phpunit highlight you've got an ErrorException, what you can do is to assert the fixture-setup is correct (fixture is the "Oh no" error) and just declare it so.
What? Yes, we turn the obstacle in front of us into the good condition just by saying so:
try {
#trigger_error('Oh no');
} catch (ErrorException $good) {
assert('Oh no' === $good->getMessage(), get_class($good));
} finally {
assert(isset($good), 'an expected exception was thrown');
}
This example helps to better describe what is going on and what we know to deal with, however the original problem still remains: Due to some error handler turning errors into exceptions, error_get_last() returns NULL as there was no error, but an exception.
Execute this code. It will show it passes.
So what is to assert is the opposite. Let's do this, turn the good condition into this bad, bad failure by negating it:
try {
#trigger_error('Oh no');
} catch (ErrorException $fail) {
assert(false, sprintf('the "%s" exception must not be thrown', get_class($fail)));
} finally {
assert(!isset($fail), 'there must not have been any exception');
}
I hope you can follow so far. First flip.
Now the fixture will only be asserted properly set-up when the expected state is given, here asserting that no ErrorException is being thrown, as we learned that would be "bad" (ruin any test of code with the error_get_last() call).
This is normally what one would expect to be the first version. We actually have already done two test runs now. One green, one red.
As long as this code does not pass, we know the fixture was not set-up and hence there is no need to even run any further tests.
As you can see testing is as easy as programming. You write the test code as-if everything is already in order, pure magic. Even when it makes no sense at all (there is no test yet, right?!) and still this is what you want to achieve.
Why is something that simple so hard? One part might be that writing the code before the test can be irritating then when writing the test. The mind is filled with expectations about the code while it should be only concentrated on the test(-code).
Don't sweat, just don't get irritated that testing then does not work first of all, that would be the same otherwise, too. A good test starts with failing very soon at the beginning. And this is exactly where we are and what we did is just to turn condition red into green. Second flip.
In testing this is also called the Happy Path, that is where it goes happily ever after and the test just tests for that what when things are unspecifically just working and unspecifically just testing for it.
But this only to side-track you a bit.
So now let's make the fixture pass this happy-path (remove the existing error handler, set the error, restore the old handler, I know, you have read this up from the manual already, right? So I can spare the links, sorry for being lazy):
try {
set_error_handler(null); // <--- this
#trigger_error('Oh no');
restore_error_handler(); // <--- restore original runtime configuration
} catch (ErrorException $fail) {
assert(false, sprintf('the "%s" exception must not be thrown', get_class($fail)));
} finally {
assert(!isset($fail), 'there must not have been any exception');
}
Et voilá, the happy path is green!
But this is only the happy path. Good tests test for others paths, too. And rigorously.
Didn't we have one? A right, yes, the one with the first assertion that ErrorException were triggered, we have that test already. What once was good despite a failure is now good again (but despite the name, on the unhappy path). Third flip.
try {
set_error_handler(null);
#trigger_error('Oh no');
restore_error_handler();
try {
#trigger_error('Oh no');
} catch (ErrorException $good) {
assert('Oh no' === $good->getMessage(), get_class($good));
} finally {
assert(isset($good), 'an expected exception was thrown');
}
} catch (ErrorException $fail) {
assert(false, sprintf('the "%s" exception must not be thrown', get_class($fail)));
} finally {
assert(!isset($fail), 'there must not have been any exception');
}
Wow, now this certainly escalated as the story evolved. And it's not even complete yet. You've spotted the one or other problem with it, right?
The initial expectation that there is the ErrorException throwing error-handler on the happy path is missing. Let's put it on top as an early check (and unset the check variable afterwards as there is the re-use for the post-assertion).
And even more importantly, ensure error_get_last() returns NULL as otherwise the test could be easily tainted for the result:
try {
#trigger_error('Oh no');
} catch (ErrorException $good) {
assert('Oh no' === $good->getMessage(), get_class($good));
} finally {
assert(isset($good), 'an expected exception was thrown');
}
unset($good);
assert(NULL === error_get_last()); // <-- this easy to miss
try {
set_error_handler(null);
#trigger_error('Oh no');
restore_error_handler();
try {
#trigger_error('Oh no');
} catch (ErrorException $good) {
assert('Oh no' === $good->getMessage(), get_class($good));
} finally {
assert(isset($good), 'an expected exception was thrown');
}
} catch (ErrorException $fail) {
assert(false, sprintf('the "%s" exception must not be thrown', get_class($fail)));
} finally {
assert(!isset($fail), 'there must not have been any exception');
}
// continue here...
It is verbose but shows all the things that are done:
awareness that triggering an error alone does not work and why
the precondition that error_get_last(); returns NULL before setting an error
that there is an ErrorException error-handler that needs to get out of the way to trigger a ture PHP error
that this error handler is re-instated as likely the system under test needs it (or should be tested with it)
Thanks to assert() statements it documents its own expectations.
Wrap it in a function and give it a useful name and a short description for what it is good for. You can - but must not - safe-guard the assertions. I normally do that inside the Phpunit test-suite so that the expected runtime-configuration is not getting lost.
Here I come to an end which hopefully is another beginning for you.
This is only one way how you could approach such hard problems, and these problems are really hard to test because it's full of side-effects here. Not only would error_get_last() pose a problem for a straight forward handling.
Yes, error handling is hard, often forgotten or attacked with a "burn-it-with-fire" attiture. At the end of the day this is not helpful when you actually need to deal with it.
And by the definition of it, writing a test for that, is.
The full example incl. simulation of an error exception throwing error handler and some of the earlier flips on 3v4l.org: https://3v4l.org/8fopq
It should go without saying that turning all errors into exceptions is some of the stupidest idea some developers have fallen for. It is just another example that error handling is hard.
Errors and exceptions are a major source of complexity and bugs
If you want get know something talk with the another human.
Thank you a lot #hakre!
And compressed above answer:
protected function generateSafelySimulatedError(\Closure $errorGeneratingFn, string $generatedErrorMsg = null): void
{
try {
set_error_handler(null);
set_exception_handler(null);
$errorGeneratingFn();
restore_error_handler();
restore_exception_handler();
try {
$errorGeneratingFn();
} catch (\ErrorException $good) {
if ($generatedErrorMsg !== null) {
$this->assertTrue($generatedErrorMsg === $good->getMessage(), get_class($good));
}
} finally {
$this->assertTrue(isset($good), 'An expected exception was thrown.');
}
} catch (\ErrorException $fail) {
$this->assertTrue(false, sprintf('The "%s" exception must not be thrown.', get_class($fail)));
} finally {
$this->assertTrue(!isset($fail), 'There must not have been any exception.');
}
}
And sample usage:
public function testCriticalErrors(): void
{
$testObject = $this->getObjectUnderTest();//Here is creation of object and also here is set_error_handler() and other similar.
$this->generateSafelySimulatedError(function (): void {
#trigger_error('Oh no');
}, 'Oh no');
$testObject->criticalErrors();//tested method like:
/*
$lasterror = error_get_last();
if ($lasterror !== null) {
//do something
}
*/
//Below other assertions if needed.
$this->expectOutputString('<html class="error"><body><h1>500</h1>Error 500</body></html>');
}

How do I do additional tests after expected exceptions are thrown?

I need to verify that the object's state is not affected by a mutator call that is expected to generate an error. I thought I could do:
function testWhatever(){
try{
// setup $obj
$this->expectException(WhateverException::CLASS);
// code that throws
}finally{
// assert that $obj's state is still valid
}
}
But I immediately realized it would certainly create some issues with PHPUnit (and it indeed does) if the code within finally also throws for whatever reason.
What are my options to perform some assertions after the exception has thrown, possibly without being too acrobatic with try/catch/rethrow and without repeating "code that throws" twice? Something with equivalent functionality to the following, which is not allowed:
function testWhatever(){
try{
// setup $obj
$this->expectException(WhateverException::CLASS);
// code that throws
}finally{
$this->expectException(null);
// assert that $obj's state is still valid
}
}
You can just use an ordinary try / catch / finally
function testFoobar()
{
// setup code
try {
// code that throws
$this->fail("Code didn't throw!");
} catch (ExpectedException $e) {
// verify exception message
} finally {
// verify other things
}
}
You could use two tests and make them depend on each other (just make your first test succeed on Exception
/**
* #depends testWhatever
*/
public function testSomethingAfterException() {
// more tests to run
}

Catch error messages from standard PHP functions with a Unit test

A bit unclear on the title, but here we go.
I am running a unit test on a method that essentially runs a strpos(). Like this:
return strpos($this->getHeaderLine($headerName), $value) !== false;
Now I also want to see what happens if I supply it an empty value. When provide an empty string, I get the following message:
strpos(): Empty needle
This message in itself is clear enough, I don't want to throw an exception here. I do want to know if it returned this message though. How would I go about doing this or do I need to rewrite my method?
Try the following:
public function testWarning()
{
$this->expectException(PHPUnit_Framework_Error_Warning::class);
$this->expectExceptionMessage("Empty needle");
strpos('meh', '');
}
This test passes, but if you comment out the expectations, it fails. There are more related classes in PHPUnit framework, like PHPUnit_Framework_Error_Deprecated, PHPUnit_Framework_Error_Notice and so on.

PHPUnit test always succeeds, even when I'm calling fail()

I'm currently trying to write some basic unit tests for a php application, unfortunately the test always succeed, even if i want them to fail. I googled for many hours, but without success. Below you can find the code which succeeds on every call:
public function testCreateArticle()
{
$articleRepository = RepositoryFactory::getArticleRepository();
$this->fail();
}
Test succeeds.
If I switch the statements (fail() first) the test fails, but since I need the articleRepository, I can't do any asserts at all. It just seems to return a success after the first line.
Does anyone have a clue what could be wrong?

Phpunit - mocking SoapFault->getMessage()

I'm connecting to a third party service using SOAP. This service will return SoapFaults some times. Because this is expected, I want to test this, by mocking the SoapFaults. There are five standard SoapFaults it will return.
Here is the start of a real SoapFault:
object(SoapFault)#7 (11) {
["message":protected]=>
string(19) "{ 'INVALID_INPUT' }"
I am interested in this message. In my code I use $e->getMessage().
catch (SoapFault $e)
{
// Catch any Soap faults and convert to an error message
switch ($e->getMessage())
{
case "{ 'INVALID_INPUT' }":
$this->addError(self::INVALID_INPUT);
return FALSE;
but I cannot figure out how to mock the SoapClient response. The SoapClient object doesn't appear to take in any input to set the message, and the method getMessage() is final, so I can't mock it.
Any ideas would be appreciated. Thanks.
There should be no need to mock SoapFault. You can just use the real exception (usually exceptions are not mocked for testing as they are Value objects) and mock the SoapClient to throw your prepared exception.
By doing so you get around not being able to mock getMessage because you build the SoapFault in your test case like shown below.
As I've had troube figuring out what exactly your problem was i build a little test case to make sure it works out. As it was there already i guess the code explains it better than i could.
Test example:
<?php
class SoapFaultTest extends PHPUnit_Framework_TestCase {
public function testSoapFault() {
$soapFault = new SoapFault("test", "myMessage");
$soapClient = $this->getMockBuilder('SoapClient')
->setMethods(array('methodOnService'))
->disableOriginalConstructor()
->getMock();
$soapClient->expects($this->once())
->method('methodOnService')
->will($this->throwException($soapFault));
$x = new Consumer();
$this->assertSame(
"InvalidInput",
$x->doSoapStuff($soapClient)
);
}
}
class Consumer {
public function doSoapStuff(SoapClient $soapClient) {
try {
$soapClient->methodOnService();
} catch(Exception $e) {
if($e->getMessage() == "myMessage") {
return "InvalidInput";
}
}
}
}
Outputs:
phpunit SoapFaultTest.php
PHPUnit 3.6.3 by Sebastian Bergmann.
.
Time: 0 seconds, Memory: 3.75Mb
OK (1 test, 2 assertions)
The assertion is kept simple but you should be easily able to adapt this for your way of handling errors
Next to what edorian answered, there should be no need to test that a third-party component works as announced. Don't write tests for components you don't have written the code (or for which you can not write code, if they are broken, they're broken and you're lost).
Just test that your code works as expected. You should be able to mock your own code.
Example: Your code will always break if code or data of it is missing, e.g. files of your application get partially deleted under circumstances. Do you write tests for such scenarios? Naturally not.
You can however write yourself an integration suite that automatically tests if certain remote dependencies provide the expected interface and responses. But I would put that suite apart from your testsuites that cover your own code-base.
Additionally you can create your own assertion functions that can be used in each testcase, for example one for SoapClient Exception Message.
I want to thank hakre for his comment. This is exactly what I wanted.
The SoapFault extends Exception, which expects an input of ($message, $code, $previous).
But the SoapFault expects ($faultcode, $faultstring, $faultactor, $detail, $faultname, $headerfault).
This is what threw me.
The $faultstring maps to the exception message.
So to mock it, I did:
$mock_soap->expects($this->once())
->method('checkVat')
->will($this->throwException(new SoapFault('a', "Error Message")));
And in my real code
$e->getMessage() now returns 'Error Message'

Categories