/usr/portage

8 Hints out of Testing-Turmoil 6

  1. Have a continuous integration solution in place. Really. If you don’t, you just burn money by writing tests. I would go so far and say, if you don’t have continuous integration, you should stop writing unit tests and do click testing. Let your CI system generate API docs, high level docs, code coverage report, testdox and every statical analysis info you generate.
  2. The definition of “tests pass” is “tests pass on the continous integration system”. “Works for me” has neither a place in the bugtracker nor everywhere else.
  3. If you can’t test it, the architecture is most likely wrong (exceptions are sessions and caching related code which is generally hard to test). Testability should be your main concern when writing code. What’s the use of fast or wonderful looking code, if you can’t repeatable prove it is working?
  4. Prefer method calls over annotations. A typo in setExpectedException will trigger a transparent error, while a typo in expectedException will lead to Obscure Test, and most likely a Mistery Guest.
  5. Run the whole test harness twice. This will hellp to identify setup/teardown bugs. Create a random test suite to identify the hard to track mistakes.
  6. Run your testsuite really often. We run it with 15 seconds delay every minute and I’m pretty happy with it.
  7. Use good test names that describe the behavior of the unit. The behavior is not the unit you test itself, that’s what I see in the code, it is something like “calling register changes the status of the user to foobar” so the good test name would be “testRegisterChangesTheStatus …”.
  8. Aim for 100% code coverage. 95% is nothing to be proud about, I can guarantee, the missing 5% will be the hardest part.

Filed under , , , & six comments & no trackbacks

Testing exceptions (2) 5

As I previously mentioned we made some effort to better check exceptions. The target is not only ensuring that a various exception is thrown but also that this exception is really the one which is expected. The result was a patch for PHPUnit to test for the exception message (which is already in) and the exception code. As Sebastian mentioned in the PHPUnit 3.2.9 release announcement, the latter is now included too. Therefore a few new options are available.

Example will fail:

<?php
    public function testException()
    {
        $this->setExpectedException('Exception', 'Exception message', 100);
        throw new Exception('Invalid message', 10);
    }

Example will pass:

<?php
    public function testException()
    {
        $this->setExpectedException('Exception', 'Exception message', 100);
        throw new Exception('Exception message', 100);
    }

Specifying exception tests with the annotations syntax:

<?php
    /**
     * @expectedException Exception error message 100
     */
    public function testException()
    {
         throw new Exception('error message', 100);
    }

Another attractive new feature is the option to use namespaces as a test organization separators. Until now, the PEAR scheme was used for PHPUnit test (_ becomes the directory separator, .php is auto-attached). This means a test was called My_ObjectTest and was supposed to be located in My/ObjectTest.php. Thanks to a really simple patch the test location stays the same, while the class name might be changed to My::ObjectTest. Happy namespacing.

Filed under , , & five comments & no trackbacks

Testing exception messages 5

Since PHPUnit 3.2.0 the former extension for exception test case (PHPUnit_Extension_ExceptionTest) has been merged back into the default test case. This allows you to use setExpextedException() in a normal test case. A simple exception test looks like that:

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testException()
    {
        $this->setExpectedException('Exception');
        throw new Exception();
    }
    /**
     * @expectedException Exception
     */
    public function testException2()
    {
        throw new Exception()
    }
}

Often this is not enough. When you use a Zend Framework alike style for exceptions (one base class to rule them all) you often throw the same exception class with different messages. To test wheither the correct exception has been thrown, I discussed with Sebastian Bergmann about introducing an contains assertion for messages and this patch was applied. So in the current PHPUnit trunk you can test exception messages:

<?php
class MyTest extends PHPUnit_Framework_TestCase
{
    public function testException()
    {
        $this->setExpectedException('Exception', 'Exception message');
        throw new Exception('Exception message');
    }
    /**
     * @expectedException Exception Exception message
     */
    public function testException2()
    {
        throw new Exception('Exception message')
    }
}

As internally PHPUnit uses an assertContains for the exception message you can even test for incomplete strings like an exception message containing a random file name.

I proposed to do the same for exception codes but Sebastian did not agree. But let’s see, maybe that will change when Zend Framework is going to use exception codes a lot.

Filed under , , & five comments & one trackback

Smarty templates and code coverage 0

PHPUnit provides a filter util to mark a piece of code as test fixture. This makes the template disappear from the coverage report and helps a lot to keep the code coverage report readable and clean. In case of Smarty you just use the builtin php-tag to execute native PHP calls:

{php}PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'TESTS');{/php}

Filed under , , , & no comments & no trackbacks

Unit testing is not enough 3

In Mental notes to myself the question was asked, if unit testing is enough. Of course not. Unit testing, especially unit testing with PHP tackles a single problem domain. This problem domain is PHP code quality. So once you have good tests for you PHP code you could assume that is works halfway fine. That’s everything. Between good PHP code and a working application there is a huge gap. There we go: JavaScript, user interface and the services your application consumes. If you have connection problems with your payment provider, a unit test does not solve that problem. But the daily execution of unit tests will eventually help you to tackle it. The JavaScript part can be addressed with a JavaScript unit testing framework, such as JsUnit. Testing the user interface and the backend through the user interface, that’s what was called “black box testing”, can be done with Selenium, which is also integrated with PHPUnit.
To write high-quality software, you have to do all of this. There are a lot of excuses, why not to do this, but they are all just excuses. To make you feel worse, this test strategy is even not sufficient, because you also need human testers. They must be really good, they do blackbox testing, find strange wording, unintuitive interfaces, page-as-cage situations, improper avocation at important conversion points, etc. pp. But a good tester is never as cheap as software, also a tester could not be controlled per command (which is good), so the hard problems need to be tackled before.

Filed under , , , & three comments & no trackbacks

Jetzt bewerben! 0

Wir suchen bei Neu.de einen Senior Software Developer (also einen, von dem ich noch was lernen kann) und einige PHP-Entwickler, die ruhig neu im Geschäft sein dürfen, aber wenigstens programmieren können sollten (das mit OOP und sinnvollem Software-Design bringen wir schon bei). Beide Stellen sind auf unserer Job-Seite genauer beschrieben. Ein paar Keywords, die einem Bewerber wenigstens gefallen sollten: Test driven development (PHPUnit), Acceptance tests mit Selenium, objektorientierte Entwicklung in PHP5, Einsatz von Jabber-Technologien, Dojo JavaScript Toolkit, AJAX, Design patterns, UML, APIs (Rest, XMLRPC), JSON. Achso: wir stehen ganz massiv auf Bewerbungen mit aussagekräftigen Referenzen, die dürfen auch ruhig so aussehen, als wollte ein Bewerber ernsthaft bei uns arbeiten.
Benefits sind Kaffee und Vittel for free, beste Musikerziehung im Bereich independent Pop/Rock/Elektro, gut gefülltes Mate-Reservoir, die Abwesenheit einer Kleiderordnung und eine Dart-Scheibe, die bespielt werden will.
Wer noch weitere Fragen hat, darf sich gerne bei mir melden (per Mail oder per Jabber)

Filed under , , , , , & no comments & no trackbacks

Xinc - Continuous integration toolkit for PHP 0

Since I setting up a preliminary unitesting server is on my todo list for the next time at work I’ve looking at CruiseControl for continuous integration to decide wheither this is worth utilizing or not. I found it a bit unhandy to integrate it in a PHP environment (we are using Zend Framework, PHPUnit and phing to name a few). Today I read about Xinc on Sebastian Bergmanns weblog (thanks by the way: it is a pleasure to work with PHPUnit every day). Maybe this is the tool I was looking for. I will evaluate (and blog about) the current state and if it is already usable.

Filed under , , , & no comments & no trackbacks

Using Phing with PHPUnit3 1

If you are interested in using Phing and PHPUnit >=3.0 together, you can just use this patch. It is heavily based on this work by Kentaro Ishitoya.

Filed under , , , , , , & one comment & no trackbacks