PHPUnit get good feedback from the test - php

this question for me is to found a way to improve my test. When i test my code, usually I use this code:
$this->assertContains('textExample', $client->getResponse()->getContent());
when the test get OK all is right, but when the test fail the feedback from phpunit is so heavy, because php unit echo to terminal all the page into have search the textExample.
I would filter $client->getResponse()->getContent()) and search textExample in the precise part of site where i search it (div, h2...) and not have that heavy feedback form phpunit.
I hope I was clear, if not i'll try to re-explain.

Why don't you use either tearDwon() or onNotSuccessfulTest() methods. This way you could handle the error and filter if you need.
For instance you could try something like this to start:
public function onNotSuccessfulTest($e) {
// inspect $e to get the information you need, for ie:
print_r(get_class_methods($e)); die();
parent::onNotSuccessfulTest($e);
}
Check here for more information.

Related

Error using Mockery/phpUnit in Laravel

I'm a novice developer trying to get a test suite started for an existing laravel app but I have not experience in testing. Right now I'm just trying to get some tests built out to get some confidence and experience to write more substantial tests. I'm trying to test a relationship on a model(I realize it's not a very sensible tests) and trying to create a mocked model object to do so(I also understand it's better to do this in memory in a sqlite db but the major goal here is to test the controllers but I don't know how to deal with the authentication issue there). I have the following simple, stupid test:
public function testFoo()
{
$lead = m::mock('Lead');
$this->mock->shouldReceive('program')->once();
$this->assertEquals($lead->program_id, $lead->program->id);
}
But I get the following error:
LeadTest::testFoo
BadMethodCallException: Received Mockery_0_Lead::getAttribute(), but no expectations were specified
I don't understand what this error is trying to tell me and I'm finding no help googling the issue or reading through the docs I can find.
I assume I'm not setting the expected return values but this is a pretty general test and it doesn't seem right to hard code expected return values. What am I missing here?
I'm just testing a Laravel relationship to make sure I have things set up/implemented correctly:
public function program()
{
return $this->belongsTo('Program');
}
The problem was that I was missing the expected return value. It should've been something like this:
$this->mock->shouldReceive('program')->once()->andReturn(someObjectOrValue);
And the assertion should've been something like:
$this->assertEquals(someObjectOrValue, $lead->program->id);
The Mockery docs are a lot more verbose than I originally thought. http://docs.mockery.io/en/latest/reference/expectations.html

phpunit check logs file

I have several integration tests with phpunit,
and in the proccess of the tests there are some logs written to files in the system.
I would like to check if a line was written during a test, is that possible?
example:
/** #test */
function action_that_writes_to_log() {
$this->call('GET', 'path/to/action', [], [], $requestXml);
//I want this:
$this->assertFileHas('the log line written', '/log/file/path.log');
}
The obvious way:
Implementing a custom assertion method, like the one you propose: assertFileHas. It's quite easy, just check if the string appears in the file. The problem you can get is that the line can already exist from another test or the same test already run. A possible solution for this is deleting the logs content before each test or test class, depending on your needs. You would need a method that deletes the logs and call it from setUp or setUpBeforeClass.
I would go with another approach: mocking the logging component, and checking that the right call is being done:
$logger_mock->expects($this->once())
->method('log')
->with($this->equalTo('the log line written'));
This makes easy to test that the components are logging the right messages, but you also need to implement a test that verifies that the logger is capable of actually writting to the file. But it's easier to implement that test once, and then just check that each component calls the logging method.

Yii - CHttpRequesterror while functional unittesting in module

When I'm trying to execute a functional unittest of a module within my Yii code, I keep receiving the following error:
CException: CHttpRequest is unable to determine the request URI.
At first, I though it was because it couldn't find the module. However, If I change the url to a wrong one, I get a correct error,s tating it couldn't find the view.
This is how my testing code looks like
public function testViewControllerModule()
{
ob_start();
Yii::app()->runController('module/controller/view');
}
Any ideas on what I might be missing?
bool.devs answer works so far.
This blog post explains the origin of the exception pretty well:
http://mattmccormick.ca/2012/09/14/unit-testing-url-routes-in-yii-framework/
In my case, I generalized the solution and have set the following variables in /www/protected/tests/bootstrap.php:
...
$_SERVER['SCRIPT_FILENAME'] = 'index-test.php';
$_SERVER['SCRIPT_NAME'] = '/index-test.php';
$_SERVER['REQUEST_URI'] = 'index-test.php';
Yii::createWebApplication($config);
Consider using 'index-test.php' instead of 'index.php' because it contains the config 'test.php' which is responsible for fixtures and maybe other test relevated configurations.
If someone has better suggestions feel free to comment :)
Kind regards
I think it's because you haven't set any server variables, i.e $_SERVER and you might be doing something like this in your controller:
Yii::app()->request ....
So before you run your test, make sure you use a fixture for the server variables also. I think this should suffice for now:
$_SERVER=array(
'REQUEST_URI'=>'index.php', // the other fields should follow
);
However to run functional tests i would recommend using SeleniumRC, you won't have to do these workarounds then, and can simulate user clicks also, i think.
Read the initial guide to Functional Testing , read the selenium rc phpunit guide, and also the CWebTestCase documentation.
Notes: You might still have to use fixtures for some variables, and i don't have much experience in testing(which is bad), so i'm not very sure if i am completely correct about selenium.

PHPUnit: Multiple assertions in a single test, only first failure seen

The next weirdness I'm seeing with PHPUnit:
class DummyTest extends PHPUnit_Framework_TestCase {
public function testDummy() {
$this->assertTrue(false, 'assert1');
$this->assertTrue(false, 'assert2');
}
public function testDummy2() {
$this->assertTrue(false, 'assert3');
}
}
As soon as the first assertion fails in a test, the rest of the test is ignored.
So (with a simple call of phpunit DummyTest.php):
The above code will display 2 tests,
2 assertions, 2 failures. What?
If I make all the tests pass, then
I'll get OK (2 tests, 3 assertions).
Good.
If I only make all the tests pass
except for assert2, I get 2 tests, 3
assertions, 1 failure. Good.
I don't get it, but PHPUnit's been around for ages, surely it has to be me?
Not only are the counts not what I'd expect, only the error message for the first failed assert in the code above is displayed.
(BTW, I'm analyzing the xml format generated by PHPUnit for CI rather than testing real code, hence the practice of multiple assertions in the one test.)
First off: That is expected behavior.
Every test method will stop executing once an assertion fails.
For an example where the opposite will be very annoying*:
class DummyTest extends PHPUnit_Framework_TestCase {
public function testDummy() {
$foo = get_me_my_foo();
$this->assertInstanceOf("MyObject", $foo);
$this->assertTrue($foo->doStuff());
}
}
if phpunit wouldn't stop after the first assertion you'd get an E_FATAL (call to a non member function) and the whole PHP process would die.
So to formulate nice assertions and small tests it's more practical that way.
For another example:
When "asserting that an array has a size of X, then asserting that it contains a,b and c" you don't care about the fact that it doesn't contain those values if the size is 0.
If a test fails you usually just need the message "why it failed" and then, while fixing it, you'll automatically make sure the other assertions also pass.
On an additional note there are also people arguing that you should only have One Asssertion per Test case while I don't practice (and I'm not sure if i like it) I wanted to note it ;)
Welcome to unit testing. Each test function should test one element or process (process being a series of actions that a user might take). (This is a unit, and why it is called "unit testing.") The only time you should have multiple assertions in a test function is if part of the test is dependent on the previous part being successful.
I use this for Selenium testing web pages. So, I might want to assert that I am in the right place every time I navigate to a new page. For instance, if I go to a web page, then login, then change my profile, I would assert that I got to the right place when I logged in, because the test would no longer make sense if my login failed. This prevents me from getting additional error messages, when only one problem was actually encountered.
On the other side, if I have two separate processes to test, I would not test one, then continue on to test the other in the same function, because an error in the first process would mask any problems in the second. Instead, I would write one test function for each process. (And, if one process depended on the success of the other, for instance, post something to a page, then remove the post, I would use the #depends annotation to prevent the second test from running if the first fails.)
In short, if your first assert failing does not make the second one impossible to test, then they should be in separate functions. (Yes, this might result in redundant code. When unit testing, forget all that you have learned about eliminating redundant code. That, or make non-test functions and call them from the test functions. This can make unit tests harder to read, and thus harder to update when changes are made to the subject of the tests though.)
I realize that this question is 2 years old, however the only answer was not very clear about why. I hope that this helps others understand unit testing better.

How to design error reporting in PHP

How should I write error reporting modules in PHP?
Say, I want to write a function in PHP: 'bool isDuplicateEmail($email)'.
In that function, I want to check if the $email is already present in the database.
It will return 'true', if exists. Else 'false'.
Now, the query execution can also fail, In that time I want to report 'Internal Error' to the user.
The function should not die with typical mysql error: die(mysql_error(). My web app has two interfaces: browser and email(You can perform certain actions by sending an email).
In both cases it should report error in good aesthetic.
Do I really have to use exception handling for this?
Can anyone point me to some good PHP project where I can learn how to design robust PHP web-app?
In my PHP projects, I have tried several different tacts. I've come to the following solution which seems to work well for me:
First, any major PHP application I write has some sort of central singleton that manages application-level data and behaviors. The "Application" object. I mention that here because I use this object to collect generated feedback from every other module. The rendering module can query the application object for the feedback it deems should be displayed to the user.
On a lower-level, every class is derived from some base class that contains error management methods. For example an "AddError(code,string,global)" and "GetErrors()" and "ClearErrors". The "AddError" method does two things: stores a local copy of that error in an instance-specific array for that object and (optionally) notifies the application object of this error ("global" is a boolean) which then stores that error for future use in rendering.
So now here's how it works in practice:
Note that 'Object' defines the following methods: AddError ClearErrors GetErrorCodes GetErrorsAsStrings GetErrorCount and maybe HasError for convenience
// $GLOBALS['app'] = new Application();
class MyObject extends Object
{
/**
* #return bool Returns false if failed
*/
public function DoThing()
{
$this->ClearErrors();
if ([something succeeded])
{
return true;
}
else
{
$this->AddError(ERR_OP_FAILED,"Thing could not be done");
return false;
}
}
}
$ob = new MyObject();
if ($ob->DoThing())
{
echo 'Success.';
}
else
{
// Right now, i may not really care *why* it didn't work (the user
// may want to know about the problem, though (see below).
$ob->TrySomethingElse();
}
// ...LATER ON IN THE RENDERING MODULE
echo implode('<br/>',$GLOBALS['app']->GetErrorsAsStrings());
The reason I like this is because:
I hate exceptions because I personally believe they make code more convoluted that it needs to be
Sometimes you just need to know that a function succeeded or failed and not exactly what went wrong
A lot of times you don't need a specific error code but you need a specific error string and you don't want to create an error code for every single possible error condition. Sometimes you really just want to use an "opfailed" code but go into some detail for the user's sake in the string itself. This allows for that flexibility
Having two error collection locations (the local level for use by the calling algorithm and global level for use by rendering modules for telling the user about them) has really worked for me to give each functional area exactly what it needs to get things done.
Using MVC, i always use some sort of default error/exception handler, where actions with exceptions (and no own error-/exceptionhandling) will be caught.
There you could decide to answer via email or browser-response, and it will always have the same look :)
I'd use a framework like Zend Framework that has a thorough exception handling mechanism built all through it.
Look into exception handling and error handling in the php manual. Also read the comments at the bottom, very useful.
There's aslo a method explained in those page how to convert PHP errors into exceptions, so you only deal with exceptions (for the most part).

Categories