I'm writing unit tests for my Shopware Plugin. I've setup the same PHPUnit environment as SwagPayPal.
What I did:
[...]
"require": {
"ext-json": "*",
"php": ">= 8.0",
"goetas-webservices/xsd2php-runtime": "^0.2.16",
"enqueue/stomp": "^0.10.16",
"shopware/core": "6.4.12.0"
},
"autoload": {
"psr-4": {
"Namespace\\Plugin\\": "src/"
}
},
"autoload-dev": {
"psr-4": {
"Namespace\\Plugin\\Test\\": "tests/"
}
},
[...]
bootstrap="tests/TestBootstrap.php"
->addActivePlugins('SwagCmsExtensions')
was removed. https://github.com/shopwareLabs/SwagPayPal/blob/10694e851a11ac60e98cdb2130e66724611ef9a6/tests/TestBootstrap.phpMy tests were all working fine. I now added the following code in one test:
$customerRepository = $this->getContainer()->get('customer.repository');
$customerRepository->upsert([$customerData], Context::createDefaultContext());
After calling upsert
it crashes with Compile Error: Cannot declare class Shopware\Core\Checkout\Promotion\Cart\PromotionProcessor, because the name is already in use
I can get it working when I run sudo rm -rf var/cache/test_*
but only once. When running it a second time it crashes again.
It seems it loads Shopware from the vendor folder of the plugin and then also from the root folder. I don't get why it's working the first time, but not a second time.
Edit: I checked all my namespace declarations in the PHP test files and I'm pretty sure they're correct. So I think it's another cause I can't find.
I just updated my tests/TestBootstrap.php
to fix my problem.
I removed the ->setClassLoader(require dirname(__DIR__) . '/vendor/autoload.php')
call, so it doesn't load the composer generated stuff anymore.
I added the following code so it adds the PSR-4 namespace prefixes for my plugin:
$pluginComposerDir = realpath(__DIR__ . '/..');
$pluginComposerJson = json_decode(file_get_contents($pluginComposerDir . '/composer.json'));
foreach (['autoload', 'autoload-dev'] as $loader) {
if (is_object($pluginComposerJson->$loader) && is_object($pluginComposerJson->$loader->{'psr-4'})) {
foreach ($pluginComposerJson->$loader->{'psr-4'} as $namespace => $path) {
$classLoader->addPsr4($namespace, $pluginComposerDir . '/' . $path);
}
}
}
So now I have best of both worlds:
autoload-dev
namespace(s) for tests.Failed Dependency: Required plugin/package "goetas-webservices/xsd2php-runtime ^0.2.16" is missing or not installed and activated
Failed Dependency: Required plugin/package "enqueue/stomp ^0.10.16" is missing or not installed and activated
Full tests/TestBootstrap.php
:
<?php declare(strict_types=1);
// based on tests/TestBootstrap.php of SwagPayPal
/*
* (c) shopware AG <[email protected]>
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
use Shopware\Core\TestBootstrapper;
if (is_readable(__DIR__ . '/../../../../vendor/shopware/platform/src/Core/TestBootstrapper.php')) {
// from Shopware root vendor dir
require __DIR__ . '/../../../../vendor/shopware/platform/src/Core/TestBootstrapper.php';
} elseif (is_readable(__DIR__ . '/../../../../vendor/shopware/core/TestBootstrapper.php')) {
// from Shopware root vendor dir
require __DIR__ . '/../../../../vendor/shopware/core/TestBootstrapper.php';
} else {
throw new Exception('TestBootstrapper not found. Please install Shopware root dependencies.');
}
$classLoader = (new TestBootstrapper())
->setProjectDir($_SERVER['PROJECT_ROOT'] ?? dirname(__DIR__, 4))
->setLoadEnvFile(true)
->setForceInstallPlugins(true)
->addCallingPlugin()
->bootstrap()
->getClassLoader();
$pluginComposerDir = realpath(__DIR__ . '/..');
$pluginComposerJson = json_decode(file_get_contents($pluginComposerDir . '/composer.json'));
foreach (['autoload', 'autoload-dev'] as $loader) {
if (is_object($pluginComposerJson->$loader) && is_object($pluginComposerJson->$loader->{'psr-4'})) {
foreach ($pluginComposerJson->$loader->{'psr-4'} as $namespace => $path) {
$classLoader->addPsr4($namespace, $pluginComposerDir . '/' . $path);
}
}
}
return $classLoader;
Edit: adjusted tests/TestBootstrap.php
to load TestBootrapper
class from Shopware root.