Showing posts with label TDD. Show all posts
Showing posts with label TDD. Show all posts

Saturday, 25 March 2017

Keeping your CLI integration tests green on Windows

Lately on a Windows system, some failing integration tests for CLI commands utilising the Symfony Console component caused me some blip headaches by PHPUnit insisting that two strings are not identical due to different line endings. The following post documents the small steps I took to overcome these headaches.

First the assertion message produced by the failing test, see the console output below, got me thinking it might be caused by different encodings and line endings; though the project was utilising an .editorconfig from the early start and the related files were all encoded correctly and had the configured line endings. The Git configuration e.g. core.autocrlf=input also was as it should be.

1) Stolt\LeanPackage\Tests\Commands\InitCommandTest::createsExpectedDefaultLpvFile
Failed asserting that two strings are identical.
--- Expected
+++ Actual
@@ @@
 #Warning: Strings contain different line endings!
-Created default 'C:\Users\stolt\AppData\Local\Temp\lpv\.lpv' file.
+Created default 'C:\Users\stolt\AppData\Local\Temp\lpv\.lpv' file.
Another deeper look at the CommandTester class yielded that it’s possible to disable the command output decoration and also to normalise the command output. So a change of the SUT preparation and a normalisation of the console output, visualised via a git diff -U10, brought the solution for this particular test.

diff --git a/tests/Commands/InitCommandTest.php b/tests/Commands/InitCommandTest.php
index 58e7114..fb406f3 100644
--- a/tests/Commands/InitCommandTest.php
+++ b/tests/Commands/InitCommandTest.php
@@ -48,21 +48,21 @@ class InitCommandTest extends TestCase
     /**
      * @test
      */
     public function createsExpectedDefaultLpvFile()
     {
         $command = $this->application->find('init');
         $commandTester = new CommandTester($command);
         $commandTester->execute([
             'command' => $command->getName(),
             'directory' => WORKING_DIRECTORY,
-        ]);
+        ], ['decorated' => false]);

// ommitted  code

-        $this->assertSame($expectedDisplay, $commandTester->getDisplay());
+        $this->assertSame($expectedDisplay, $commandTester->getDisplay(true));
         $this->assertTrue($commandTester->getStatusCode() == 0);
         $this->assertFileExists($expectedDefaultLpvFile);
Since the SUT had a lot of integration test for its CLI commands, the lazy me took the shortcut to extend the CommandTester and using it, with desired defaults set, instead of changing all of the related command instantiations.

<?php

namespace SUT\Tests;

use Symfony\Component\Console\Tester\CommandTester as ConsoleCommandTester;

class CommandTester extends ConsoleCommandTester
{
    /**
     * Gets the display returned by the last execution of the command.
     *
     * @param bool $normalize Whether to normalize end of lines to \n or not
     *
     * @return string The display
     */
    public function getDisplay($normalize = true)
    {
        return parent::getDisplay($normalize);
    }

    /**
     * Executes the command.
     *
     * Available execution options:
     *
     *  * interactive: Sets the input interactive flag
     *  * decorated:   Sets the output decorated flag
     *  * verbosity:   Sets the output verbosity flag
     *
     * @param array $input   An array of command arguments and options
     * @param array $options An array of execution options
     *
     * @return int The command exit code
     */
    public function execute(
        array $input,
        array $options = ['decorated' => false]
    ) {
        return parent::execute($input, $options);
    }
}
So it's a yay for green CLI command integration tests on Windows from here on. Another measure for the SUT would be to enable Continuous Integration on a Windows system via AppVeyor, but that’s a task for another commit 85bdf22.

Wednesday, 7 November 2007

Utilizing designer toys as an extreme feedback device

extreme feedback deviceIn response to Nick Halstead's Programming Tips Competition I dug a bit in my blog's idea queue for something related. The idea I picked includes some thoughts on how to gently prod the implementation of developer testing/specifying as an everyday team practice, assuming a head-nod/good-to-go from management. So today you won't see any code, as this is more related to the area of team building and process adoption. Instead of starting with the 'dictatorial' hammer and thereby possibly discouraging T2 developers or scaring away T3 developers, it would be wisely to use a fun and far more important attention creating approach. As this idea popped up on my mind I found a really suitable designer toy called Totem Doppelganger from Anton Ginzburg, consisting of three stackable look-a-like ghosts. I guess an excellent match to disenchant the initial 'mystics' of developer testing/specifying. As them are separable they can be used to accompany and indicate the ranged skill-development of each involved developer/team and thereby act as an extreme feedback device for both parties.

An example scenario could be:

At the beginning of process adoption every developer/team without or less previous knowledge might get two feedback devices(ghosts), which will be reduced to one on the path to the expected knowledge. One device might remain to signal the willingness to spread the gained knowledge to other struggling with adoption the practices or new team members, this tends to the direction of building a Developer Testing Master. In the case of not practicing pair-programming they can even act as a reminder to apply developer testing/specifying until it becomes a flesh-and-blood habit.

Sunday, 7 October 2007

Adding some BDD flavour to the PHPUnit framework

Influenced by an article written by David Astel and the latest 'interest resurrecting' blog entries of Pádraic Brady, I was looking for a way to bend over the PHPUnit test-centric vocabulary to a more behaviour-centric one. The motivation for this 'NLP' is best justified by a quote from David Astel's paper "... if you want to change how you think it can help to first change your language".

In Sebastian Bergmann's latest slides about Advanced PHPUnit Topics, he already provides a possibility to weaken the default test-centric vocabulary by using the annotation feature of his framework to enable the use of customizable and thereby freely nameable test/behaviour specifying methods.

The following code listing re-shows the use of the aforementioned annotation feature of PHPUnit to change the verb from test for verifying the system under development(SUD) to should for specifying the SUD.

<?php
require_once 'PHPUnit/Framework.php';

class CartSpecification extends PHPUnit_Framework_Testcase
{
/**
* @test
*/
public function shouldContainTwoProducts()
{
// only assert available
}
/**
* @test
*/
public function shouldBeEmptyAfterSuccessfullOrder()
{

}
/**
* @test
*/
public function shouldIncreaseAmountOnSameProductAddition()
{

}
}
Wrapping the assertations
When starting to specify the behaviour of the SUD i.e. a shopping cart PHPUnit provides a collection of assertations out of the box. As assert in the domain of testing means to verify something and as the goal of BDD is to promote/support a mindshift from verfication to specification this doesn't just feel natural, so I wanted to bend the verb assert over to the more appropriate sounding verb should. This can be achieved by writing an Adapter for the already existing Assert class of PHPUnit. The following listing outlines such an Adapter class i.e. called Expect, wrapping the already builtin assertations.
<?php
require_once 'PHPUnit/Framework/Assert.php';

class PHPUnit_Framework_Expect extends PHPUnit_Framework_Assert
{
public static function shouldNotInclude($needle, $haystack, $message = '')
{
self::assertNotContains($needle, $haystack, $message = '');
}
public static function shouldInclude($needle, $haystack, $message = '')
{
self::assertContains($needle, $haystack, $message = '');
}
public static function shouldEqual($expected, $actual, $message = '', $delta = 0, $maxDepth = 10)
{
self::assertEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10);
}
public static function shouldNotEqual($expected, $actual, $message = '', $delta = 0, $maxDepth = 10)
{
self::assertNotEquals($expected, $actual, $message = '', $delta = 0, $maxDepth = 10);
}
...
}
Making the expectations available
To make use of the additional defined vocabulary it's necessary to create a class called Specification, which is nearly indentical to the PHPUnit_Framework_TestCase class and differs only in it's naming and the derivation from the aforedefined PHPUnit_Framework_Expect class instead of PHPUnit_Framework_Assert. The following code shows an excerpt of this class with the necessary adjustments.
<?php
require_once 'PHPUnit/Framework.php';
require_once 'PHPUnit/Framework/MockObject/Mock.php';
require_once 'PHPUnit/Framework/MockObject/Matcher/InvokedAtLeastOnce.php';
require_once 'PHPUnit/Framework/MockObject/Matcher/InvokedAtIndex.php';
require_once 'PHPUnit/Framework/MockObject/Matcher/InvokedCount.php';
require_once 'PHPUnit/Framework/MockObject/Stub.php';
require_once 'PHPUnit/Runner/BaseTestRunner.php';
require_once 'PHPUnit/Util/Filter.php';

PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');

if (!class_exists('PHPUnit_Framework_Specification', FALSE)) {

abstract class PHPUnit_Framework_Specification extends PHPUnit_Framework_Expect
implements PHPUnit_Framework_Test,
PHPUnit_Framework_SelfDescribing
{
// same as PHPUnit_Framework_Testcase to maintain mockability etc.
...
}

}
At last the two new classes have to be addedd to the framework by adding two require statements to PHPUnit_Framework.php as shown next.
<?php

require_once 'PHPUnit/Util/Filter.php';

PHPUnit_Util_Filter::addFileToFilter(__FILE__, 'PHPUNIT');

require 'PHPUnit/Framework/SelfDescribing.php';
require 'PHPUnit/Framework/AssertionFailedError.php';
require 'PHPUnit/Framework/Assert.php';

require 'PHPUnit/Framework/Expect.php';

require 'PHPUnit/Framework/Error.php';
require 'PHPUnit/Framework/Notice.php';
require 'PHPUnit/Framework/IncompleteTest.php';
require 'PHPUnit/Framework/SkippedTest.php';
require 'PHPUnit/Framework/Test.php';
require 'PHPUnit/Framework/TestFailure.php';
require 'PHPUnit/Framework/TestListener.php';
require 'PHPUnit/Framework/TestResult.php';
require 'PHPUnit/Framework/ExpectationFailedException.php';
require 'PHPUnit/Framework/IncompleteTestError.php';
require 'PHPUnit/Framework/SkippedTestError.php';
require 'PHPUnit/Framework/SkippedTestSuiteError.php';
require 'PHPUnit/Framework/TestCase.php';

require 'PHPUnit/Framework/Specification.php';

require 'PHPUnit/Framework/TestSuite.php';
require 'PHPUnit/Framework/Warning.php';
require 'PHPUnit/Framework/Constraint.php';
require 'PHPUnit/Framework/ComparisonFailure.php';
?>
Using the new vocabulary
To make use of the new defined behaviour-centric vocabulary for specifying a SUD, it's specification 'driver' now has to be derived from the PHPUnit_Framework_Specification class.
<?php
require_once 'PHPUnit/Framework.php';
require_once 'Cart.php';
require_once 'Product.php';

class Cart extends PHPUnit_Framework_Specification
{

protected $cart = null;

protected function setUp()
{
$this->cart = new Cart();
}
/**
* @test
*/
public function shouldContainTwoProducts()
{
$this->cart->addProduct(new Product('SDT-10001', 'Product 1'));
$this->cart->addProduct(new Product('WRO-55000', 'Product 2'));

// should is available
$this->shouldEqual(2, sizeof($this->cart->getProducts()));

// assert still available as PHPUnit_Framework_Expect is derived from PHPUnit_Framework_Assert
$this->assertEquals(2, sizeof($this->cart->getProducts());
}
/**
* @test
*/
public function shouldBeEmptyAfterSuccessfullOrder()
{
...
}
/**
* @test
*/
public function shouldIncreaseAmountOnSameProductAddition()
{
...
}
}
To run the specification of the SUD the PHPUnit Cli is run as known and it's still possible to make use of it's testdox feature like in the following console excerpt.
C:\Apache2.2\htdocs\spec>phpunit --testdox Cart.php
PHPUnit 3.1.4 by Sebastian Bergmann.

Cart
- Should contain two products
- Should be empty after successfull order
- Should increase amount on same product addition
Of course this PHPUnit vocabulary 'hack' is far away from the featuresets provided by JBehave or RSpec, but maybe it's useful to someone until the first PHP BDD tools hit the community stage. Also make sure to keep the PHPSpec project on your radar if you're interested in BDD.

Tuesday, 22 May 2007

PHP in Action book review

Over the last few days I got the chance to skim through the upcoming Manning release "PHP in Action: Modern Software Practices for PHP" by Dagfinn Reiersøl et al. The reviewed book is separated into four main parts, covering lots of interesting topics in a good and fluent writing style.

The first part covers basic tools and concepts applied to PHP, which includes software design principles, object-oriented guidelines and the use of design patterns. If you are a continuous reader of specialized publications you might have read or heard of most of them, but the authors know always how to relate them to the PHP language. Were suitable the object-oriented concepts and guidelines are compared to the JAVA language, to support the learning process by showing similarities and varieties, without awaiting the reader to be an JAVA expert.

The second part addresses the approach for developing and designing more reliable web applications by applying TDD(Test-Driven Development) as a learning, design and quality assurance tool for the development process. It starts with traversing through the TDD cycle by using examples which are based upon the SimpleTest framework. If you're favouring the use of PHPUnit the provided knowledge can be easily transformed and might encourage you to get a feeling of the TDD flow while transforming it. Further on more advanced testing techniques like using mocks and stubs are covered for the isolated testing of components. The outlined 'Red, Green and Refactor' cycle is closed by examples of basic refactorings and other cataloged refactorings(i.e. Replace Conditional with Polymorphism) in a PHP manner. Finally this part of the book is rounded off by sketching the refactoring of procedural code towards object-oriented code and how to test your applications front-end via web tests supported by the SimpleTest framework.

In the third part the main focus is on the specifics of web presentation and user interfaces. The authors show how to achieve the desirable separation of presentation and the main domain logic by using several techniques reaching from plain old PHP to template engines and to the adoption of XSLT in combination with some general presentation logic patterns(Composite View, Two Step View). Thereafter a switch is made to illumine the architectural MVC pattern and how it can be used to identify commands and actions made within the user interface and how to map these to the application domain logic. In this regard classic PoEAA patterns like Page Controller and Front Controller are covered. The part is finally closed by thoughts and insights on input validation and form handling in context of possible strategies, stumbling blocks and implementation solutions.

The last part of the book deals with object-oriented data access, reaching from database abstraction, to overcoming the object-relational impedance mismatch, to the generalizing and generation of SQL statements and to supportive design patterns like Data Access Object and Active Record.

The point I liked most about this book is how it sets previous 'heavy impact' publications like Patterns of Enterprise Application Architecture and Refactoring: Improving the Design of Existing Code in relation to the PHP programming language. This might save you some mental translation work on covered areas and serve as an entry point for further research. I'd like to recommend this book as as very valuable reading to anyone who has already mastered the fundamentals of software development with PHP and is looking for further input to push its own development fitnesse and its way to develop 'not-your-average' web applications.

Monday, 29 January 2007

Manual setup guide of PHPUnit 3.0.3 for PEARless people

Since I got currently no internet connection at home the PEAR-way of installing PHPUnit is a nope for me. So once again I had to install it manually and spend to much time on this simple task and came up with an quick setup guide. The PHPUnit source is available here.

Step 1:

Start to create two environement variables called PHP_CLI and PHPUNIT_HOME via the system properties(win + break keys). For the environment variable named PHP_CLI you set the path to your PHP executable and for the PHPUNIT_HOME you set the path to where you put the PHPUnit source like C:\php5.2.1\PHPUnit-3.0.3 . I keep it there because I think TDD is a must for serious web development with PHP 5 and therefor a needed core feature.

Step 2:
Rename the pear-phpunit.bat script to phpunit.bat and put it in your path. On my box it's suited in the PHP folder which is already in the path environment variable.

Step 3:
Now open the bat file for editing. Since the manual installation instructions given by Sebastian Bergmann are confusing for me and I never get it running quickly the first time, I came up with an dummy-prove solution. This is were the beforehand defined environement variables are coming in very handy. You just have to add the following line to the bat file and you'r done.

%PHP_CLI% %PHPUNIT_HOME%\PHPUnit\TextUI\Command.php %*
Step 4:
At last add the PHPUNIT_HOME directory to your include path in the php.ini. Now fire up your prompt and check for the current version via phpunit --version and you should see the following output.

PHPUnit 3.0.3 by Sebastian Bergmann

Now you are ready to step into TDD with PHP 5.