Laravel PHPUnit testsuite class not found when used from vendor folder

534 views Asked by At

I have added a Laravel package as local repository to my composer.json:

...
    "repositories": [{
        "type": "path",
        "url": "../external-tests"
    }],
    "require": {
        ...
        "shaedrich/external-tests": "dev-develop",
        ...
    }
...

I've also added it to my testsuites element in phpunit.xml file:

...
<testsuite>
    <file>./vendor/shaedrich/external-tests/tests/SomeAdditionalTestsTest.php</file>
</testsuite>
...

Package's composer.json:

{
  "name": "shaedrich/external-tests",
  "description": "",
  "keywords": ["Laravel"],
  "authors": [
    {
      "name": "Sebastian Hädrich",
      "email": "[email protected]"
    }
  ],
  "homepage": "https://github.com/shaedrich/external-tests",
  "require": {
    "php": "^8.1",
    "laravel/framework": "^8.0"
  },
  "require-dev": {
    "phpunit/phpunit": "^9.0",
    "orchestra/testbench": "^6.0",
    "phpstan/phpstan": "^0.12"
  },
  "license": "MIT",
  "autoload": {
    "psr-4": {
      "Shaedrich\\ExternalTests\\": "src/"
    }
  },
  "autoload-dev": {
    "psr-4": {
      "Shaedrich\\ExternalTests\\Tests\\": "tests/"
    }
  },
  "extra": {
    "laravel": {
      "providers": [
        "Shaedrich\\ExternalTests\\Providers\\ExternalTestsServiceProvider"
      ]
    }
  },
  "scripts": {
    "test": "vendor/bin/phpunit -c ./phpunit.xml --colors=always",
    "analysis": "vendor/bin/phpstan analyse"
  }
}

I used Yeoman Laravel Package Scaffolder for the project setup.

The test case has the following code:

<?php

namespace Shaedrich\ExternalTests\Tests;

use Illuminate\Support\Facades\Http;
use Illuminate\Testing\TestResponse;
use PHPUnit\Framework\Attributes\DataProvider;

class SomeAdditionalTestsTest extends TestCase
{
    public static function provideFilePaths(): array
    {
        return [
            'protected' => [ '/profile' ],
        ];
    }

    /**
     * @test
     * @dataProvider provideFilePaths
     */
    public function fails_if_file_path_is_accessible(string $path): void
    {
        $response = Http::baseUrl(implode(':', [ config('app.url'), config('app.port') ]))->get($path);
        $this->assertFalse($response->status() === 200);
    }
}

But when I try to run my tests via php artisan test, it shows the following error:

Fatal error: Class 'Shaedrich\ExternalTests\Tests\TestCase' not found in …

If I understand the error message correctly, composer manages to autoload SomeAdditionalTestsTest.php but not any files used inside that class

1

There are 1 answers

0
shaedrich On

Thanks to @matiaslauriti for hinting that the autoloading via autoload-dev doesn't work here the way the package is intended to work.

...
"autoload": {
    "psr-4": {
      "Shaedrich\\ExternalTests\\": "src/"
    }
  }
  "autoload-dev": {
    "psr-4": {
      "Shaedrich\\ExternalTests\\Tests\\": "tests/"
    }
  },
...

This is due to the directory (and namespace), the tests are in. The confusion happened because the tests/ directory is meant for tests that test the package, not the application. However, the tests in question are indeed designed to test the application.

.
├── src/
│   └── Testing/
│       └── Feature/
│           └── SomeAdditionalTest.php
└── tests/
    └── SomeInternalTest.php

So, the solution is to move the tests to an autoloadable directory and keep the tests/ directory for internal tests:

- namespace Shaedrich\ExternalTests\Tests;
+ namespace Shaedrich\ExternalTests\Testing\Feature;

\Shaedrich\ExternalTests\Testing\Feature is no autoloaded via autoload instead of autoload-dev.

That results in the following phpunit.xml <testsuite />:

       <testsuite name="Plug'n'Play external tests">
            <directory suffix="Test.php">./vendor/shaedrich/external-tests/src/Testing</directory>
       </testsuite>