0

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": "sebastian.haedrich@mailbox.org"
    }
  ],
  "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

shaedrich
  • 5,457
  • 3
  • 26
  • 42
  • can you show me how did you include `vendor/autoload.php` file ? – Abdulla Nilam Mar 01 '23 at 09:34
  • Laravel handles that out of the box by doing `require __DIR__.'/../vendor/autoload.php';` inside public/index.php and artisan respectively. – shaedrich Mar 01 '23 at 09:51
  • You need to share the `composer.json` of `shaedrich/external-tests`, and could you also share the namespace of `SomeAdditionalTest.php`? – matiaslauriti Mar 01 '23 at 16:33
  • @matiaslauriti I added the two files. – shaedrich Mar 01 '23 at 17:59
  • 1
    @shaedrich your issue is that you are trying to load an `autoload-dev` when that is never going to happen... `autoload-dev` outside your main `composer.json` will never be read, because you server something with `autoload` (`require`), even adding it to `require-dev` will not work... `require-dev`/`autoload-dev` is local to that package... this will never work... – matiaslauriti Mar 01 '23 at 18:44
  • As you can read in the package's github, you have to go to the package and run `test` locally on that folder, in your case `cd ../shaedrich/external-tests && php artisan test` (but you would have to run `composer install` on that folder first – matiaslauriti Mar 01 '23 at 18:48
  • @matiaslauriti Maybe, there is a misunderstanding: The tests from the package are not meant to test the package but the application the package is required in. Maybe `tests/` is not the right directory in that case. – shaedrich Mar 01 '23 at 20:49
  • There is no missunderstanding, when you want to use a package (composer package), it must be tested separately, what you want is a simil package, something that is like a composer package but not 100% a package. You do not have to use composer for this in this case – matiaslauriti Mar 01 '23 at 20:58
  • I agree. The package must be tested. But that's another matter. The tests currently provided by the package are tests that extend the applications test suite by some general tests used in several applications so that they don't have to be copied and pasted. – shaedrich Mar 01 '23 at 22:55

1 Answers1

0

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>
shaedrich
  • 5,457
  • 3
  • 26
  • 42