When writing PHPUnit tests, some of them turn out to take quite long to execute. To check certain functions, I need to check a lot of different combinations of variables, and this leads to a very long test.
Is is possible to tell PHPUnit how far the test has progressed so it can output the intermediate progress for the test to the command line? Now it is just waiting there for 2 minutes without any indication of progress.
I am just looking for an extra progress indicator that would be part of PHPUnit, and not just a custom echo, which I can write myself just fine.
I am sorry, but this is not possible.
However, if you need to invoke the same piece of code with different data, for instance call the same method with different arguments, then you should have a look at data providers.
Related
I have a PHP file that will only connect to DB and displays the resultset in an HTML table. How do we create a unit test script for such PHP file?
Thanks a lot in advance.
If you did not defined any function on your code (and don't want to), this is not an ideal scenario. You can still write a PHPUnit test starting PHP's built-in web server and perform HTTP requests (using Guzzle?). Then, ensure that what's being generated is consistent with the records of your database.
However, it may not be really needed to write tests only for this functionality, since it can be easily tested by hand and you risk to write a lot of duplicate code between your script and the test(s).
First of all, I don't know if it is called Unit Testing. If it has a different name, feel free to correct me.
I'm currently developing web applications like this.
Let's say I'm developing a form to save values into database. I develop HTML and PHP. I time to time press F5 in Browser and check if HTML/jQuery has no bugs and PHP doesn't give errors like missed semicolon.
When it is complete and everything is ready to be tested, I start testing small pieces of my code. Like;
-Do $_POST array correctly obtains values from form file? (I test with print_r)
-Is "$email" variable correctly sanitized to be a valid e-mail? (I test it with different posibilities, eg: aaa#bbb, aa#bb.com, a##b.net etc.)
-Is the form submitted passed all controls, and successfully inserted to the database? (I check my MySQL table.)
-Does the form shows error/success messages correctly?
-...etc.
If it works with correct values, and fails with wrong values; I believe the form is working as intended and there is no bugs, so I move onto other things.
Instead of doing this, I want to ensure things works perfectly, otherwise notifies me about the problem without spamming F5 on browser.
Like this;
<?php
/* Unit Testing Start --
-ensure: isset($_POST['submit']) returns TRUE;
-ensure: isset($email) returns TRUE;
-ensure: isValidEmail($email) returns TRUE;
-ensure: connectDatabase() returns TRUE;
-ensure: getMysqlAffectedRows() returns 1;
-ensure: hasErrors() returns false;
*/
?>
My form codes, uses the functions I posted above.
When it runs, it should show me a message like this: (preferably logging it also)
Test complete. Tested (6) possibilities, (4) succeeded, (2) failed.
Failed 1: isValidEmail() returned FALSE, expected: TRUE.
Failed 2: getMysqlAffectedRows returned NULL/0, expected INTEGER 1.
Something like this would save me alot of time and make it easier to maintain my codes.
I do NOT want to do this:
$email = 'xxx#yyy.com';
echo isValidEmail($email) ? 'true' : 'false';
Then I have to erase those lines from my PHP scripts. Tests has to stay there forever, unless I manually delete them. They should be like comments so in production website, they won't be executed. However, in my development PC, I'll install whatever I need to install and those comments has to be parsed/logged.
So, yeah. That's all. Now onto the questions:
Is it something possible to do with PHP? If so, how can I do this?
What is it called, Unit Testing, or what?
How do you guys test whatever you develop?
How do you guys manage to develop huge web applications without worrying; "If I change this function, the entire website may break."? Also, how are you being sure changing function didn't break anything? X page may work fine but Y may be broken because of something you didn't think before. Like, division by 3 on X page may work fine, but division by 0 on Y page will definitely give errors, but you only checked X page?
I'll really be glad if you can reply to my questions and help me be a better developer.
Thanks!
Yes, automated testing is a cornerstone of solid software development, precisely because it's impossible to keep checking everything manually by clicking in the browser. Unit tests are typically "technical" tests that make sure a specific "unit" (typically a function or class) returns expected return values for a specified input. Functional testing tests larger units of code for correct behavior. Acceptance testing tests the final application from the point of view of a user.
There are a number of frameworks and tools to cover these different needs:
PHPUnit - the de facto unit testing framework for PHP
Behat - a testing framework focussing on offering "business readable" tests
Codeception - a framework trying to be both readable and technical
All of the above have excellent documentation which ease you into the thinking of working with unit tests. I recommend you start by reading into PHPUnit, then look at what Behat or Codeception can offer you.
As general advice: Test whether your code behaves correctly. Do not test "what is does", test whether you get the result you expect when you do something. For example, don't test isset($_POST['submit']). That's too detailed, there's no point in covering every single line of your application with a test. Instead, test larger units of code. Test that when you submit a form with known given values that your code correctly redirects you to the next page. Or test that your authentication system correctly denies access to unprivileged users. You want tests to read like this:
Scenario: Login
Given I am on the login page
When I log in as user "Jon" with the password "foo"
Then I should be logged in
Or:
Scenario: Deny unprivileged user
Given I am logged in as the user "Jon" with access level 1
When I try to access the action "restricted"
Then I should be denied access
Not:
Scenario: Login
Given I submit a form with the values "Jon" as username and "foo" as password
When I check the $_POST array I should see "Jon" in the key "name" and ...
...
The above can literally be tests in Behat by the way.
To make sure these tests you wrote are actually worth something, you need to run them on a regular basis. Maybe you create a trigger in your version control system to run your test suite automatically when code is checked in and deny checkins which fail tests. Best though is if you have a Continuous Integration server set up which regularly gets the latest code from your repository and runs the tests on it. If you set this up properly, you'll automatically be notified about all sorts of edge problems that easily go overlooked during regular development. For instance, the CI server should try to set up and run the application from scratch every time and may alert you that there's a problem getting a dependency from a third party you depend on, or that there's a problem in your database migration scripts. Things you wouldn't have noticed otherwise, since you don't always fetch dependencies and don't always re-run your migration scripts.
In the end you're aiming for having your code "exercised" automatically on a continual basis from all possible angles. That's the only way to find problems with it.
For CI software, personally I like TeamCity a lot, but Jenkins and Hudson are very popular and there are a ton of other CI tools.
Acording to WikiPedia:
In computer programming, unit testing is a method by which individual
units of source code, sets of one or more computer program modules
together with associated control data, usage procedures, and operating
procedures, are tested to determine if they are fit for use.
I'm guessing this what you are doing can be called UnitTesting.
The best way to UnitTest is though a well know framework. There are few for PHP. I guess the most popular is PHPUnit. Appart from testing it does other cool things like code coverage report (I'm sure other frameworks do it as well).
I work on Eclipse and I have PHPUnit integrated with my IDE. While developing I don't have to switch between windows. I just run a test and see does my code work or not. It saves lots of time.
It sounds like you should check out the simpletest.
I was wondering, I have a few functions in PHP that're not called every time but still are included in my files on each load. Does it still run the code even if your not calling the function at that time? The reason I'm asking, the codes in my function are expensive to run CPU wise and I don't call them every time and want to make sure if there not called they do not run the code within the function.
Thank you
In short, a function that isn't explicitly called does not run. However, here is a short what and why we use functions that I found.
A function is a "black box" that we've locked part of our program
into. The idea behind a function is that it compartmentalizes part of
the program, and in particular, that the code within the function has
some useful properties:
It performs some well-defined task, which will be useful to other
parts of the program.
It might be useful to other programs as well; that is, we might be
able to reuse it (and without having to rewrite it).
The rest of the program doesn't have to know the details of how the
function is implemented. This can make the rest of the program
easier to think about.
The function performs its task well. It may be written to do a
little more than is required by the first program that calls it,
with the anticipation that the calling program (or some other
program) may later need the extra functionality or improved
performance. (It's important that a finished function do its job
well, otherwise there might be a reluctance to call it, and it
therefore might not achieve the goal of reusability.)
By placing the code to perform the useful task into a function, and
simply calling the function in the other parts of the program where
the task must be performed, the rest of the program becomes clearer:
rather than having some large, complicated, difficult-to-understand
piece of code repeated wherever the task is being performed, we have
a single simple function call, and the name of the function reminds
us which task is being performed.
Since the rest of the program doesn't have to know the details of
how the function is implemented, the rest of the program doesn't
care if the function is reimplemented later, in some different way
(as long as it continues to perform its same task, of course!). This
means that one part of the program can be rewritten, to improve
performance or add a new feature (or simply to fix a bug), without
having to rewrite the rest of the program.
Functions are probably the most important weapon in our battle against
software complexity. You'll want to learn when it's appropriate to
break processing out into functions (and also when it's not), and how
to set up function interfaces to best achieve the qualities mentioned
above: reuseability, information hiding, clarity, and maintainability.
http://www.eskimo.com/~scs/cclass/notes/sx5.html
I am developing some project with CodeIgniter and write unit tests and web tests in SimpleTest. I've noticed that my tests are not deterministic, i.e. they produce different outputs in time. I mean the test cases that should be strictly deterministic, not relying on random variables etc.
The tests look like affecting each other. Quite often, when everything goes okay, I have let's say 100 passed tests, but when I write a new test method that fails, then several other tests also do fail. But often after correcting the problem in my failing test case and re-running whole test suite 2-3 times whole suite gives a pass again.
This happens with WebTestCases generally.
Do you have any idea what could be the problem?
I do not modify any class variables that are shared etc.
I've glance at the code of SimpleTest (more or less, it's big to analyze whole flow quickly) and it looks like the instance of browser is re-created before launching different tests.
The thing that is the strangest is that after re-running, some errors disappear, and finally, all of them. Is there some caching involved in this?
I'll be grateful for hints as there is really not much documentation / blog entries / forum posts about SimpleTest in the web, except its API on the website.
Things it might be:
Caching - are you caching bad results
somewhere in the chain?
Misunderstanding - Are you sure you
are testing the right things?
Bad Data - If you are testing this on
top of a database, and the failure
corrupted the data in the database,
you might see results like you
mention.
(edit: moved the answer as a separate post)
Huh, I made quite thorough investigation and it seems that there is a bug in SimpleTest library.
They use fsockopen for opening connection, then send request via fwrite, and then incorrectly fetch response from socket. What I mean: it can happen that we read 0 bytes from socket, but we're not done, as we falsely assume, cause the server can be busy, and send data later, while we prematurely ended reading. That way, we haven't read whole response and we do tests against only partial response, causing it to fail.
I want to be prompted for an input when I run a PHPUnit test case and then to use that input as part of the test. In other words, I want to use a dynamic input value for a field.
How can I do this?
Short Answer: You shoudn't
Long Asnwer: You really shoudn't because it massively violates the goals of unittesting
While it's easy to do echo "Input for Test 7: "; $input = fgets(STDIN); it isn't how unittesting works.
Depending on your usecase there might be a reason to do so but i can't think of any and since the solution is trivial i use the rest of the post describing why you might not want to do this.
Unittests are meant to be run often. Really really often. Many people use a setup that runs the Tests everytime you edit a file. But at least everytime before you check code into the Sourcecode management system.
Do you really want to write 1 (or 10 or 50) lines everytime just so your testsuite runs ?
Also the biggest benefit of Unittests is that you have a system in place that takes care of one very important question "if i put in the same thing here as yesterday, does it still provide the same output / does it still work". So i don't see a point in putting in something different every time.
If you go one step further and use an automated system to run your tests and send an email in case the tests fail there isn't anyone there to provide input so you couldn't use that.. and one big reason to use unittesting is excatly that ;)
If you are really sure about what you doing: Sorry for the 'rant'
Edit (your reply only showed up after posting for me): The same thing sort of goes for other dynamic input. Imho you want to make sure the result is reproducable. If you just need a temporary variable/foldername/key/something thats not a big problem. I'd just use md5(mt_rand()) or something. Even so it's nice if you can set up your tests in a way so that isn't necessary