Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Testing with PHP. How can I ensure things to be running correctly?

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;

  1. -Do $_POST array correctly obtains values from form file? (I test with print_r)
  2. -Is "$email" variable correctly sanitized to be a valid e-mail? (I test it with different posibilities, eg: aaa@bbb, [email protected], a@@b.net etc.)
  3. -Is the form submitted passed all controls, and successfully inserted to the database? (I check my MySQL table.)
  4. -Does the form shows error/success messages correctly?
  5. -...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 = '[email protected]';
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!

like image 334
Lisa Miskovsky Avatar asked Feb 28 '13 09:02

Lisa Miskovsky


2 Answers

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.

like image 137
deceze Avatar answered Sep 28 '22 08:09

deceze


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.

like image 32
Lukasz Kujawa Avatar answered Sep 28 '22 09:09

Lukasz Kujawa