Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Specify Laravel Package

codeception/specify

Trait for BDD-style specifications in PHPUnit/Codeception. Lets you write tests with describe/it-like blocks, shared setup, and clear expectations, improving readability while staying compatible with standard PHP unit testing workflows.

View on GitHub
Deep Wiki
Context7
## Getting Started
### Minimal Setup
1. **Installation**
   ```bash
   composer require --dev codeception/specify:^2.0
  • Note: Requires PHP 7.4+ (minimum). For PHP 8.1, no additional changes are needed.
  1. Basic Usage Import the trait in your test class:

    use Codeception\Specify;
    
    class MyTest extends \Codeception\Test\Unit
    {
        use Specify;
    }
    
  2. First Use Case Replace traditional assert blocks with specify():

    public function testUserCreation()
    {
        $user = User::create(['name' => 'John']);
    
        specify('the user has a valid name', function () use ($user) {
            $user->name->shouldBe('John');
        });
    
        specify('the user is saved', function () use ($user) {
            User::where('id', $user->id)->shouldHaveCount(1);
        });
    }
    

Where to Look First

  • Documentation: Codeception Specify Docs (if available) or GitHub README.
  • Example Tests: Check tests/ in the package repo for real-world usage.
  • Migration Guide: Review PHP 7.4+ Changes for breaking changes.
  • CI/CD: Verify your environment uses PHP 7.4+ (required for 2.0.0).

Implementation Patterns

Workflows

  1. Descriptive Test Blocks Replace verbose assert chains with readable specify() blocks (unchanged):

    public function testOrderProcessing()
    {
        $order = Order::create(['status' => 'pending']);
    
        specify('order starts as pending', function () use ($order) {
            $order->status->shouldBe('pending');
        });
    
        $order->markAsPaid();
        specify('order updates to paid', function () use ($order) {
            $order->refresh()->status->shouldBe('paid');
        });
    }
    
  2. Data-Driven Specifications Use specify() with loops or factories (unchanged):

    public function testUserRoles()
    {
        $roles = ['admin', 'editor', 'guest'];
    
        foreach ($roles as $role) {
            specify("a $role has correct permissions", function () use ($role) {
                $user = User::factory()->create(['role' => $role]);
                $user->can($role)->shouldBeTrue();
            });
        }
    }
    
  3. Integration with Codeception Works seamlessly with Codeception’s actors (unchanged):

    class UserCest
    {
        use Specify;
    
        public function _before(Actor $I)
        {
            $I->wantTo('test user workflow');
        }
    
        public function testLogin(Actor $I)
        {
            $I->amOnPage('/login');
            specify('login form loads', function () use ($I) {
                $I->see('Email');
            });
        }
    }
    
  4. Combining with PHPUnit Mix specify() with PHPUnit’s @dataProvider (unchanged):

    public function testEdgeCases()
    {
        $this->specifyDataProvider('edgeCaseProvider', function ($input, $expected) {
            $result = process($input);
            $result->shouldBe($expected);
        });
    }
    

Integration Tips

  • Laravel Testing: Pair with Laravel\LaravelTestCase for HTTP tests (unchanged):
    use Laravel\LaravelTestCase;
    use Codeception\Specify;
    
    class FeatureTest extends LaravelTestCase
    {
        use Specify;
    }
    
  • Custom Assertions: Extend Specify for domain-specific specs (unchanged):
    trait CustomSpecify
    {
        public function specifyPaymentIsValid($payment)
        {
            specify('amount is positive', function () use ($payment) {
                $payment->amount->shouldBeGreaterThan(0);
            });
        }
    }
    
  • PHP 8.1 Features: Leverage typed properties or match expressions in specify() closures:
    specify('user type is correct', function () use ($user) {
        match ($user->role) {
            'admin' => true,
            default => false,
        }->shouldBeTrue();
    });
    

Gotchas and Tips

Pitfalls

  1. PHP Version Compatibility

    • Breaking Change: PHP 7.4+ required for 2.0.0. Upgrade if using PHP 7.3 or lower.
    • Symptoms: Tests fail with PHP version mismatch or undefined method errors.
    • Fix: Update composer.json:
      "config": {
          "platform": {
              "php": "7.4"
          }
      }
      
  2. Scope Leaks (unchanged) Avoid referencing outer variables without use:

    // ❌ Fails
    specify('user exists', function () {
        $user->id; // Error!
    });
    
    // ✅ Correct
    specify('user exists', function () use ($user) {
        $user->id;
    });
    
  3. Overusing specify() (unchanged)

    • Prefer logical grouping over granularity. Example:
      // ✅ Grouped
      specify('user validation', function () use ($user) {
          $user->validate()->shouldBeEmpty();
          $user->errors->shouldBeEmpty();
      });
      
      // ❌ Overly granular
      specify('no validation errors', function () use ($user) {
          $user->validate()->shouldBeEmpty();
      });
      specify('errors array is empty', function () use ($user) {
          $user->errors->shouldBeEmpty();
      });
      
  4. Codeception-Specific Quirks (unchanged)

    • Ensure ActorTestCase closures access $I via use ($I).
    • Avoid state pollution in dynamic tests.

Debugging

  1. Failed Specifications

    • Errors show the specify() block description in failure messages:
      1) Tests\UserTest::testCreation
      specify 'user is saved' failed: User with id [1] not found.
      
  2. PHP 8.1 Strict Typing

    • If using PHP 8.1, enable strict_types=1 in test files for type safety:
      declare(strict_types=1);
      
      public function testStrictTypes()
      {
          specify('integer input', function () {
              (1)->shouldBe(1); // Passes
              ("1")->shouldBe(1); // Fails in strict mode
          });
      }
      
  3. CI/CD Pipeline

    • Add PHP version check to CI (e.g., GitHub Actions):
      jobs:
        test:
          runs-on: ubuntu-latest
          steps:
            - uses: actions/checkout@v3
            - uses: shivammathur/setup-php@v2
              with:
                php-version: '8.1'
      

Tips

  1. Naming Conventions (unchanged) Use imperative mood:

    • ✅ "shows error message"
    • ❌ "should show error message"
  2. Dynamic Specifications (unchanged) Generate blocks dynamically:

    $testCases = collect([1, 2, 3]);
    $testCases->each(function ($input) {
        specify("processes $input correctly", function () use ($input) {
            process($input)->shouldBe($input * 2);
        });
    });
    
  3. Extending Functionality (unchanged) Add custom specify* methods:

    trait ExtendedSpecify
    {
        public function specifyModelHasAttribute($model, string $attribute, $value)
        {
            specify("model has $attribute=$value", function () use ($model, $attribute, $value) {
                $model->$attribute->shouldBe($value);
            });
        }
    }
    
  4. Legacy Code Migration

    • Use both assert* and specify() during transition:
      public function testHybrid()
      {
          assertTrue(true); // Legacy
          specify('new spec style', function () {
              true->shouldBeTrue();
          });
      }
      
    • Tooling: Use phpstan or psalm to detect deprecated patterns post-migration.
  5. PHP 8.1 Performance

    • Enable JIT in PHP 8.1 for faster test execution:
      ; php.ini
      opcache.jit_buffer_size=100M
      opcache.jit=tracing
      
    • Profile with Xdebug to identify bottlenecks in `specify
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
hexters/coinpayment
rjcodes/rjcms
act-training/laravel-permissions-manager
alimarchal/laravel-chart-of-accounts
babenkoivan/elastic-scout-driver
mkwebdesign/filament-watchdog-v5
renatomarinho/laravel-page-speed
zedmagdy/filament-business-hours
renatovdemoura/blade-elements-ui
devgeek/beacon-admin
benjamin-rqt/data-watcher-bundle
atriumphp/atrium
sandermuller/package-boost-laravel
sandermuller/boost-skills
redaxo/core
yusufgenc/filament-api-forge
l3aro/rating-star-for-filament
leek/filament-subtenant-scope
anil/file-picker
broqit/fields-ai