In my Beyond Frameworks talk, I explained how a component-based architecture can help answer some of the important (i.e. expensive!) questions you might face when creating long-lived apps that rely on a PHP framework. In this series of blog posts, I’m going to look at how to go about creating and working with components.

I’ve started work on creating the components for my simple app. The first component is repustateApi, which will be a PHP client for Repustate.com’s semantic analysis API. With the component’s metadata all done, and the decision made to start with unit tests, let’s get the unit tests written and running.

The First Unit Tests

Repustate’s API is extremely simple to use, making it the ideal choice for my first semantic analysis client. It’s very low risk to knock up a client and see if their API does the job; if the API isn’t suitable under heavy testing, and I’m forced to try someone else’s semantic analysis API, I haven’t lost much time in the attempt.

As a result, my initial unit tests can be extremely simple:

namespace Gradwell\RepustateApi;

class ClientTest extends \PHPUnit_Framework_TestCase
{
        public function setUp()
        {
                $this->_apiKey = '';
        }

        public function testCanCreateClient()
        {
                // create the client with a valid key
                $client = new Client($this->_apiKey);

                // did it work?
                $this->assertTrue($client instanceof Client);
        }

        public function testCanRetrieveSentimentScoreForTextByJson()
        {
                // setup
                $client = new Client($this->_apiKey);
                $text = "this is a happy piece of text";

                // do the test
                $score = $client->callScoreForText($text, 'json');

                // evaluate result here
                $this->assertTrue ($score !== false);
        }

        public function testCanRetrieveSentimentScoreForUrlByJson()
        {
                // setup
                $client = new Client($this->_apiKey);
                $url = "http://www.stuartherbert.com";

                // do the test
                $score = $client->callScoreForUrl($url, 'json');

                //evaluate result here
                $this->assertTrue ($score !== false);
        }
}

… and the skeleton class needed to execute those tests is just as simple:

namespace Gradwell\RepustateApi;

class Client
{
        protected $apiKey = null;

        public function __construct($apiKey)
        {
                $this->setApiKey($apiKey);
        }

        public function setApiKey($apiKey)
        {
                $this->validateApiKey($apiKey);
                $this->apiKey = $apiKey;
        }

        public function validateApiKey($apiKey)
        {
                // @TODO
        }

        public function callScoreForText($text, $format = 'json')
        {
                // placeholder
                return false;
        }

        public function callScoreForUrl($url, $format = 'json')
        {
                // placeholder
                return false;
        }
}

Remember, at this stage, all I need to do is create unit tests that

  • can be executed, and
  • will fail

to allow me to model the API that this component will provide to the outside world. By the time I’m finished, both the unit tests and the Gradwell\RepustateApi\Client class will look quite different :)

Where The Unit Tests And PHP Code Goes

In our skeleton, tests go into the src/tests/unit-tests folder, and the PHP code that the component will install into /usr/share/php does into the src/php folder.

Because we’re using a PSR0-compliant autoloader for all components, it’s extremely easy to translate the name of a class into its full filename on disk.

  • Gradwell\RepustateApi\Client goes into the file src/php/Gradwell/RepustateApi/Client.php
  • Gradwell\RepustateApi\ClientTest goes into the file src/tests/unit-tests/Gradwell/RepustateApi/ClientTest.php

This approach means that, if needed, we can scale to hundreds of components inside a single app, and still only need the one autoloader.

The Component’s Folder Structure So Far

If I take the component structure, and dump it out using the ‘tree’ command, here’s a list of which files have gone where:

├── build.properties
├── build.xml
├── dist
│   └── repustateApi-0.1.0.tgz
├── LICENSE.txt
├── package.xml
├── README.md
├── src
│   ├── bin
│   ├── data
│   ├── php
│   │   └── Gradwell
│   │       └── RepustateApi
│   │           └── Client.php
│   ├── tests
│   │   ├── functional-tests
│   │   ├── integration-tests
│   │   └── unit-tests
│   │       ├── bin
│   │       ├── bootstrap.php
│   │       ├── php
│   │       │   └── Gradwell
│   │       │       └── RepustateApi
│   │       │           └── ClientTest.php
│   │       └── www
│   └── www
└── vendor
    └── php
        └── gwc.autoloader.php

In the next blog post later this evening, I’ll show you have to run the tests in your component, both from the command-line, and from inside Netbeans.

Comments are closed.