Month: March 2012

Behat + FuelPHP = RESTful Testing Happiness

If you’ve been following my recent posts, you know I’ve been working more lately with Behat for resting some REST services. In this post I showed you how to get things set up for some testing. In this post, I’ll show you how to use a custom class that I’ve put together to make a reusable system for testing REST.

For those that want to cut to the chase, I’ve posted some example code to github showing the code for the two different sides of the equation – the Behat testing and the PHP framework side (I went with FuelPHP because I was already familiar with it and it makes RESTful interfaces dead simple). The key is in the FeatureContextRest.php file that uses the Guzzle client to make the HTTP requests over to the framework. It provides some handy contexts that make it easy to create Scenarios.

So, still with me? Good – I’ll show you how to get my sample scripts installed so you can see my example in action. In the repository you’ll find two different directories – “fuel” and “behat”. In each you’ll find some files:

behat

  • features/index.features:
    An example set of Scenarios that use the REST testing contexts to create, find and deleting a “User” from the system
  • features/bootstrap/FeaturesContextRest.php:
    The key to the puzzle, the implementation of some context methods for use in Behat

fuelphp

  • fuelphp/classes:
    These are the example models and controllers you can drop into your Fuel install to have them “magically” work (with any recent version of the framework).

This is assuming you already have Behat installed and working and have set up FuelPHP on a host somwhere. For our example, we’ll just use http://behat-test.localhost:8080” Here’s what to do:

  1. Start by copying over the FeaturesContextRest.php file to the “features/bootstrap” directory of your Behat installation alongside the default FeaturesContext.php.
  2. Copy over the behat.yml configuration file into your testing root (the same level as the “features” directory) and update the base_url value for your hostname.
  3. Take the “classes” directory and copy over its contents to the location of your FuelPHP installation – if you’re familiar with the structure of the framework, this is simple…it just goes in “app/classes”.
  4. You’ll need a database to get this working, so you’ll need to get the FuelPHP ORM stuff configured and working in your install. Be sure to update your config.php to automatically load the “orm” module.
  5. Make a database for the project and use the init.sql to create the “users” table.
  6. To test and be sure our models/controllers are working right, hit your host in a browser, calling the “User” action like: “http://behat-test.localhost:8080/user”. This should call what’s in Controller_User::get_index(). It’ll probably just return an empty result though, since there’s nothing for it to pull.
  7. To use the FeaturesContextRest.php, be sure that you include that file into your default FeaturesContext.php file and that your class “extends FeaturesContextRest”.

So, if all has gone well, you have all the pieces in place to get started. Let’s start with a sample Scenario to show you how it all works:

Scenario: Creating a new User
	Given that I want to make a new "User"
	And that its "name" is "Chris"
	When I request "/user/index.json"
	Then the response is JSON
	And the response has a "userId" property
	And the type of the "userId" property is numeric
	Then the response status code should be 200

If you’ve used Mink in the past, so of this will seem familiar. This doesn’t use Mink, however, and I’ve opted to use Guzzle as the client for the backend to replace some of the browser interactions. Really, we don’t need all of the fancy interface interaction Mink gives, so this streamlined interface is more useful.

In this example, we’re creating a user with a property “name” of “Chris” and sending that off to the “/user/index.json” endpoint. A few tests are included like: checking the response code, seeing if the return value has a “userId” property, etc. If all went well and the user was created (this is a POST, so it calls “post_index” in the controller), this test should pass with flying colors….green, hopefully. 🙂

The key is in the phrases “to make a new” (POST), “to find a” (GET) and “to delete a” (DELETE) to tell the tests which verb to use.

Hopefully this library will be useful to some folks out there – I’m going to be improving it as I work on more tests for some current projects to ensure better quality of the software.

Advertisement

From the Start: Setting up Behat testing

In a previous post I showed you how to use HTTP Auth with the Goutte driver in Behat testing. I want to take a step back and show you how I even got to that point with a simple guide to installing the tool and creating your first tests. In a future post, I’ll show the (super simple) integration you can do with Jenkins to execute the tests and plug in the results.

First off, a definition for those not sure what Behat is:

Behat was inspired by Ruby’s Cucumber project and especially its syntax part (Gherkin). It tries to be like Cucumber with input (Feature files) and output (console formatters), but in core, it has been built from the ground on pure php with Symfony2 components.

And, for those not sure what Cucumber is:

Cucumber lets software development teams describe how software should behave in plain text. The text is written in a business-readable domain-specific language and serves as documentation, automated tests and development-aid – all rolled into one format.

These are both tools that implement something called behavior-driven development, the practice of approaching testing from a more natural angle, allowing tests to be written in “plain English” (or the language of your choosing with Behat) and executed at a domain level rather than a code level (as unit tests would). Behat makes this super simple and it really only takes a few minutes to get it up and running.

For my examples, I’m going to be working on a Linux-based system (CentOS actually) but the same kinds of ideas apply to other platforms too, just modified slightly for things like pathing. So, let’s get started…first off, the installation. Personally, I recommend the Composer method for installation – it just makes it easier to get everything you need without having to think hardly at all.

Here’s a set of commands (linux command line) to get everything set up for a basic project structure:

mkdir behat-testing-ftw; cd behat-testing-ftw;
curl -s http://getcomposer.org/installer | php
vi composer.json

Inside the composer.json file, enter the stuff from the Behat instructions here (the JSON format), then we can run composer on it:

php composer.phar install

At this point you should see a bunch of things being installed in the “Installing dependencies” section (at the time of this post, that includes things like symfony/finder, symfony/dependency-injection and behat/gherkin). Once this is finished, you should have a directory structure similar to:

Chriss-MacBook-Pro:behat-testing-ftw chris$ ls
bin		composer.json	composer.lock	composer.phar	vendor

Behat should be magically installed in the bin/ directory – to test it out, try this:

Chriss-MacBook-Pro:behat-testing-ftw chris$ bin/behat

If all goes well, you should see a big red error talking about “features” not existing. This is good – we’ll fix this now by making the testing base for Behat. Thankfully, it makes this easy too:

Chriss-MacBook-Pro:behat-testing-ftw chris$ bin/behat --init
+d features - place your *.feature files here
+d features/bootstrap - place bootstrap scripts and static files here
+f features/bootstrap/FeatureContext.php - place your feature related code here

Your directory should now look like this:

Chriss-MacBook-Pro:behat-testing-ftw chris$ ls
bin		composer.json	composer.lock	composer.phar	features	vendor

The new features directory is where your Behat tests will live. If you look in there now, there’s not much – just a bootstrap directory with a FeatureContext.php file in it. This file is where you’ll define any custom rules you might need to use outside of the pre-defined ones Behat (and later Mink) come with. If you re-run Behat again, you should see:

Chriss-MacBook-Pro:behat-testing-ftw chris$ bin/behat
No scenarios
No steps
0m0.001s

So, let’s give Behat something to do now – Behat tests are organized in “feature” files. Let’s make a simple one for illustration and call it “sample.features” and put some content in it:

cd features
vi sample.feature

And put the following inside it:

Feature: Testing Behat install
        This is a testing feature to see if everything
        is working correctly

        Scenario: My first test
                When I run "ls"
                Then I should see the file "composer.json"

By default, Behat doesn’t come with any contexts pre-defined (you can see this by executing /bin/behat -dl) so we’ll need to make some for our new feature. Thankfully, Behat makes this simple too (sensing a theme here?) – if you run behat again, you should get something similar to:

eature: Testing Behat install
  This is a testing feature to see if everything
  is working correctly

  Scenario: My first test                      # features/sample.feature:5
    When I run "ls"
    Then I should see the file "composer.json"

1 scenario (1 undefined)
2 steps (2 undefined)
0m0.051s

You can implement step definitions for undefined steps with these snippets:

    /**
     * @When /^I run "([^"]*)"$/
     */
    public function iRun($argument1)
    {
        throw new PendingException();
    }

    /**
     * @Then /^I should see the file "([^"]*)"$/
     */
    public function iShouldSeeTheFile($argument1)
    {
        throw new PendingException();
    }

Se those last few lines? That tells you exactly what you’ll need to drop into the FeaturesContext.php file to make things work. The key to the matching is in the DocBlock comments – there’s regular expression matches in there that Behat tries to use when it’s executing the tests. So, let’s update our FeaturesContext with some new code:

vi features/bootstrap/FeatureContext.php

And insert into the class the following:

[php]
/**
* @When /^I run "([^"]*)"$/
*/
public function iRun($command)
{
exec($command,$result);
$this->output = $result;
}

/**
* @Then /^I should see the file "([^"]*)"$/
*/
public function iShouldSeeTheFile($fileName)
{
if (!in_array($fileName,$this->output)) {
throw new Exception(‘File named ‘.$fileName.’ not found!’);
}
}
[/php]

This code tells Behat to execute the $command (via exec), return the results to the “output” property and then check to see if the $fileName is in the list. As long as you were in the main “behat-testing-ftw” directory when you executed this, all the tests should come up green:

Feature: Testing Behat install
  This is a testing feature to see if everything
  is working correctly

  Scenario: My first test                      # features/sample.feature:5
    When I run "ls"                            # FeatureContext::iRun()
    Then I should see the file "composer.json" # FeatureContext::iShouldSeeTheFile()

1 scenario (1 passed)
2 steps (2 passed)
0m0.016s

To see how it looks when tests fail, try changing the filename in the sample.feature to something like “composer.json-foo” and you’ll see that step turn red.

So, that’s pretty much it – that’s, in a nutshell how to get Behat testing up and running (via the Composer option). There’s a few minor things that I came across when I was trying to execute the Composer and Behat tools, but those usually stemmed from missing PHP functionality/packages not being installed on the server. Those were solved with a quick “yum install” call for the needed functionality.

I hope to continue this series and talk next about getting Mink up and working to add some really useful features to Behat. I’ve been using it for testing a REST service, so that’s one of the end goals.

Behat and HTTP Auth (and Goutte)

So I’ve been trying out Behat for some REST testing recently and came across an interesting situation – I needed to send HTTP Auth credentials as a part of my test. Of course, there’s a method for this on the Session object (setBasicAuth) but it’s not implemented as a default phrase. It took me a bit to make it to the (now logcial) point that I needed to set these before I used the “Given I am on…” phrase to go to the page.

So, to accomplish this, I set up a custom “Given” phrase to set them: “Given that I log in with ‘username’ and ‘password'” so that my full Scenario looks like:
[php]
Scenario: Get the main Index view
Given that I log in with "myuser" and "mypass"
And I am on "/index/view"
Then the response should contain "TextFromPageTitle"
[/php]

And the code is super simple:

[php]
/**
* Features context.
*/
class FeatureContext extends BehatMinkBehatContextMinkContext
{
/**
* @Given /^that I log in with "([^"]*)" and "([^"]*)"$/
*/
public function thatILogInWithAnd($username, $password)
{
$this->getSession()->setBasicAuth($username,$password);
}
}
[/php]

Hope this helps someone else out there trying to send HTTP Auth pre-connection. I’m sure there’s probably an easier way that I’m missing, but this seemed the simplest to me.

Ideas of March

It’s March 15th and you know what that means….only a month left for the procrastinators to do their taxes in the US. Well, actually, that’s not what I’m really talking about here. Last year a whole host of people write up posts titled “Ideas of March” and this year’s no different. Several members of the PHP community are jumping in with there thoughts on blogging – here’s some of mine.

Blogging is great, don’t get me wrong…I love it when I can Google for something and find that someone, somewhere has done exactly what I need. This historical record of shared knowledge is one of the things that makes the web great. Of course, it can also sometimes do more harm than good. “But I thought you were going to write about how blogging is a good thing,” you ask. Well, I believe it inherently is, but with a few caveats:

  • Blogs are only as good as their authors:
    Not everyone out there is a clear, excellent writer (I know I’m not) and, as a result, sometimes the message of a post can get lost in poor wording. What’s a solution to this? Blog more often! That’s right, it’s just like anything else – the more you do something, the better at it you get. You start getting into a certain frame of mind when you’re fingers to the keys and you learn little “mind tricks” (no Jedi here) on how to best get your message across. You don’t have to be an amazing writer to be a clear one.

  • Dates, Versions & Code:
    This one’s a tough one, especially for us tech bloggers. I can’t tell you the number of times that I’ve found what I thought I needed in my Google results only to go over to a post and discover that I have no idea when it was written. The URL gives no clue and there’s not a date to be found. This drives me nuts and if your blog dosen’t have dates on the post, go change that. Right now. I’ll wait here.

    Additionally, something that can make for a lot less frustration for people coming to your posts later are two things – somehow tagging or mentioning what version of a language the post relates to (“this post was written against PHP 5.2.5”) and trying to keep the code up to date. Yes, I know this second request requires a bit more commitment on your part, but people would sing your praises if you took the time to do it. Even if it’s just an update to a post that say, “I found a better way to do this…” in a more recent version of the language/tool.

  • More than just a “brain dump”:
    I’ve seen several people use their blogs as a sort of “brain dump” – a place for them to post things that they just want to remember later on. This is all well and good, but don’t forget that blogs aren’t just about code snippets and tutorials. Sometimes you need to share a bit about you and what you’re passionate about too. Take some time to sit and reflect on what you do on a daily basis and think about how knowing that process could help others. I’d encourage you to write not only code-related posts, but also keep the rest of the world up to date on the interesting things you’re doing. Nothing builds communities like people sharing more than just code.

Finally, I’d like to end this post jammed full of suggestions with one final challenge – get out there and share. My recommendations aside, if all you do is write up one or two posts this month (and keep going) with a few paragraphs each, I think the web would be a better place. Sharing knowledge is what it’s all about and if you discover something, no matter how small, you could be sharing exactly what someone needs. Remember, just because you think it’s simple, doesn’t mean someone new to the tech does….get out there and share!

Leaving SoftLayer

For those that know me, you know I’ve been working here at SoftLayer for about the last year and a half. I’ve definitely enjoyed my time here, it’s time to move on. My last day here will be a week from today. Following that I’ll be moving over to another local Dallas company called iSight Partners where I’ll be using some of the skills I’ve learned here at SoftLayer to help improve their current application set and create new, easier ways for their customers to consume the reports and data the company generates.

Here’s a description of the company from their website:

iSIGHT Partners specializes in physical, electronic and human intelligence services. We provide reliable and actionable threat intelligence to our clients’ security and fraud investigation teams, which helps them proactively counteract all phases of criminal electronic and physical attacks against digital assets.

Our suite of products complements our customers’ Risk Mitigation Teams by alerting them to emerging threats that require action and providing guidance during critical incidents. Our intelligence sources help IT teams prioritize their workflow and ensure that they are working on the most important threats and vulnerabilities first. (They can work hard on an issue all day, but if it’s not the right issue, their time is wasted and your company is put at risk.)

I’d also like to publicly thank a few folks at SoftLayer before I go:

  • First off my team who’ve taught me a lot about not only the technology we use but how to be (and not be) a leader: Stephen Johnson, Dan Hudlow, Adam Shaw, Varrence Minor, Allan Siongco, Richard Morgan, Shahmir Noorani, Steve Bartnesky, Kevin Holland, Diana Harrelson, Theo Shu and our epic QA folks – David Borne, Jaime Barriga, Reynaldo Guzman and Janeth Paredes.
  • Next comes Duke Skarda who has graciously allowed the Dallas PHP User Group to meet here at the SoftLayer offices (and provided us with food and drinks everytime!)
  • To Logan Reese and Kelly Morphis for mentoring me when I started with the company and for being there as excellent sources with all the answers

If you’re looking around for a good PHP shop to work at in the Dallas area, you’d do well to take a look at the openings that SoftLayer currently has (personally I suggest the “Interface Development” option…that’s the group I’ve been working in and it’s been a fun one).