rmiller/behat-spec
Behat extension that integrates with PhpSpec to prevent fatal errors on missing classes or methods. Automatically generates specs and examples when Behat encounters undefined domain objects, then can run phpspec to create the code.
Install the package in your Laravel project (dev dependency):
composer require --dev rmiller/behat-spec:^0.5
Configure Behat (behat.yml):
extensions:
RMiller\BehatSpec\Extension\BehatSpecExtension\BehatExtension:
path: vendor/bin/phpspec # Laravel's vendor/bin path
config: path/to/phpspec.yml # Optional: Custom PhpSpec config
Configure PhpSpec (phpspec.yml):
extensions:
RMiller\BehatSpec\Extension\BehatSpecExtension\PhpSpecExtension: ~
First Use Case:
Product::namedAndPriced()).vendor/bin/behat
phpspec run.Define a Feature:
Feature: Product Catalog
Scenario: Add a product
Given a product named "Laptop" and priced £999 was added to the catalogue
public function aProductNamedAndPricedWasAddedToTheCatalogue($name, $price) {
$product = Product::namedAndPriced($name, $price); // ❌ Missing class/method
$this->catalogue->add($product);
}
Run Behat:
[BehatSpec] Product class not found. Generate spec? (y/N) y
spec/ProductSpec.php):
namespace spec;
use PhpSpec\ObjectBehavior;
use Product;
class ProductSpec extends ObjectBehavior
{
public function it_is_initializable()
{
$this->shouldHaveType(Product::class);
}
public function it_has_a_namedAndPriced_method($name, $price)
{
$this->namedAndPriced($name, $price)->shouldReturnAnInstanceOf(Product::class);
}
}
Auto-Generate the Class:
phpspec run:
[BehatSpec] Run phpspec run to create Product? (y/N) y
src/Product.php):
namespace App;
class Product
{
public static function namedAndPriced($name, $price)
{
// TODO: Implement method
}
}
Iterate:
namedAndPriced).Product.php and re-run specs:
vendor/bin/phpspec run
Laravel Service Container:
// In a Behat service provider
$this->app->bind(Product::class, function () {
return new Product();
});
Eloquent Models:
make:model:
# phpspec.yml
rerunner:
commands: [describe, exemplify, "php artisan make:model"]
CI/CD Automation:
# Example: Non-interactive Behat + PhpSpec run
vendor/bin/behat --no-interaction && \
vendor/bin/phpspec run --no-interaction
Custom Paths:
vendor/bin paths:
# behat.yml
extensions:
RMiller\BehatSpec\Extension\BehatSpecExtension\BehatExtension:
path: vendor/bin/phpspec
PhpSpec Configuration:
app_path() for spec/config paths:
# phpspec.yml
rerunner:
config: app_path('phpspec.yml')
Interactive Prompts in CI:
--non-interactive flags or script responses:
echo "y" | vendor/bin/behat
PHP 8.x Compatibility:
Product::namedAndPriced(string $name, float $price)).composer.json:
"require-dev": {
"phpspec/phpspec": "3.6",
"behat/behat": "3.8"
}
Class Overwriting:
phpspec run generates a class that conflicts with existing Laravel classes (e.g., User), the package won’t detect it. Solution:
phpspec.yml:
suites:
app:
namespace: App
psr4_prefix: App
exclude:
- "App/Models/User" # Skip existing models
Namespace Conflicts:
phpspec.yml matches Laravel’s composer.json autoload paths:
# phpspec.yml
suites:
app:
namespace: App
psr4_prefix: App
Laravel Artisan Conflicts:
phpspec run to generate Eloquent models, conflicts may arise with Laravel’s migrations. Tip:
php artisan make:model Product --spec
Verbose Logging:
behat.yml:
default:
extensions:
RMiller\BehatSpec\Extension\BehatSpecExtension\BehatExtension:
debug: true
Manual Spec Generation:
vendor/bin/phpspec describe App/Product
Check PhpSpec Run Commands:
phpspec run works standalone:
vendor/bin/phpspec run --no-interaction
Forking the Package:
RMiller\BehatSpec\Extension\BehatSpecExtension\PhpSpecExtension.laravel config option to phpspec.yml.Custom Commands:
phpspec run commands in phpspec.yml:
rerunner:
commands: [describe, exemplify, "php artisan make:model"]
Pre/Post-Hooks:
BeforeScenario):
// In a Behat service provider
$this->getServiceContainer()->set('behat_spec_hook', function () {
return new class {
public function beforeScenario(BeforeScenarioEvent $event) {
// Custom logic before BehatSpec runs
}
};
});
Non-Interactive Mode:
ConsoleIO class:
// In a Behat extension
$this->getServiceContainer()->set('behat_spec.console_io', function () {
return new class extends \Symfony\Component\Console\ConsoleIO {
public function ask($question, $default = null) {
return $default; // Auto-answer
How can I help you explore Laravel packages today?