During office hours I work on a large PHP Application, we use a service oriented architecture and the application exposes a number of API’s. Recently we have been using Behat and writing BDD tests in Gherkin to test the behaviour of our various APIs.
When developing I always use XDebug’s remote debugging functionality to examine application flow and to debug issues as they arise. Our integration tests populate the app’s database with data and set up a number of other resources. If a test is failing its really handy to be able to trigger XDebug breakpoints and walk through the execution of the API call under test while this known state is set up.
Here is a quick example of how it’s done:
The Gherkin Test (with some contrived steps):
Feature: Xdebug example
As a Behat user
I want to debug API methods using xdebug
To facilitate debugging failing tests
Scenario: Basic HTTP Request
Given I am using Behat
When I call the api method
Then I should hit a breakpointAnd an example FeatureContext implimentation:
/** * Features context. */ class FeatureContext extends BehatContext { /** * Initializes context. * Every scenario gets it's own context object. * * @param array $parameters context parameters (set them up through behat.yml) */ public function __construct(array $parameters) { // Initialize your context here } /** * @Given /^I am using Behat$/ */ public function iAmUsingBehat() { // Dummy given step } /** * @When /^I call the api method$/ */ public function iCallTheApiMethod() { // create a new cURL resource $ch = curl_init(); // set URL and other appropriate options curl_setopt($ch, CURLOPT_URL, "http://behat-test.dev/api.php"); curl_setopt($ch, CURLOPT_HEADER, false); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); // The key to getting xdebug to break on breakpoints is this cookie curl_setopt($ch, CURLOPT_COOKIE, 'XDEBUG_SESSION=netbeans-xdebug'); // grab URL and pass it to the browser $data = curl_exec($ch); // close cURL resource, and free up system resources curl_close($ch); } /** * @Then /^I should hit a breakpoint$/ */ public function iShouldHitABreakpoint() { // Dummy then step } }
The important bit in this sample is the line:
curl_setopt($ch, CURLOPT_COOKIE, 'XDEBUG_SESSION=netbeans-xdebug');
This sets a cookie which is picked up by XDebug. Xdebug then attempts to connect to your IDE inline with your xdebug settings in php.ini. This example uses CURL for simplicity but it’s possible to add cookies to Zend Frameworks Http Client and any other good HTTP client class.
All you have to do now is open your IDE or debugging client and start a debugging session. Then drop to the command line and use the behat command to run your tests. When the step containing the HTTP call is executed xdebug should connect to your IDE and break at any point you set.
Over the next day or two I’ll be looking to see if a tighter integration is possible. It would be good to trigger a debugging session from a UI test (via Mink’s feature context file perhaps).
Happy debugging!
“It would be good to trigger a debugging session from a UI test”
have you tried the $session->setCookie(‘XDEBUG_SESSION’, ‘netbeans-xdebug’);
I would use phpstorm as it is better imo for debugging:
$session->setCookie(‘XDEBUG_SESSION’, ‘PHPSTORMKEY’);
hi man, I ran into a problem i was trying to avoid curl way and using the client returned from mink/behat and its driver goutte, but now ran into a blockade
it seems on a POST is not letting me send contents like:
$this->client->request($method, $base.$url, array(), array(), array(), $contents);
it let’s me set headers though, but not sure how to solve this problem now…
HELP!