这是我的 symfony 项目,我正在其中练习功能测试,当我测试我的功能时出现这样的错误。
这里,发生我的错误的代码部分:\
<?php
namespace App\Tests;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use App\Entity\Category;
class AdminControllerCategoriesTest extends WebTestCase
{
public function setUp():void
{
parent::setUp();
$this->client = static::createClient();
$this->entityManager = $this->client->getContainer()->get('doctrine.orm.entity_manager');
$this->entityManager->beginTransaction();
$this->entityManager->getConnection()->setAutoCommit(false);
}
public function tearDown():void
{
parent::tearDown();
$this->entityManager->rollback();
$this->entityManager->close();
$this->entityManager = null; //avoid memory leaks
}
public function testTextOnPage()
{
$crawler = $this->client->request('GET', '/admin/categories');
$this->assertSame('Categories list', $crawler->filter('h2')->text());
$this->assertContains('Electronics', $this->client->getResponse()->getContent());
}
public function testNumberOfItems()
{
$crawler = $this->client->request('GET', '/admin/categories');
$this->assertCount(21, $crawler->filter('option'));
}
}
这里是我的.env,我有数据库连接:
# In all environments, the following files are loaded if they exist,
# the latter taking precedence over the former:
#
# * .env contains default values for the environment variables needed by the app
# * .env.local uncommitted file with local overrides
# * .env.$APP_ENV committed environment-specific defaults
# * .env.$APP_ENV.local uncommitted environment-specific overrides
#
# Real environment variables win over .env files.
#
# DO NOT DEFINE PRODUCTION SECRETS IN THIS FILE NOR IN ANY OTHER COMMITTED FILES.
#
# Run "composer dump-env prod" to compile .env files for production use (requires symfony/flex >=1.2).
# https://symfony.com/doc/current/best_practices.html#use-environment-variables-for-infrastructure-configuration
###> symfony/framework-bundle ###
APP_ENV=dev
APP_SECRET=018d7408d23791c60854cbb4fc65b667
###< symfony/framework-bundle ###
###> doctrine/doctrine-bundle ###
# Format described at https://www.doctrine-project.org/projects/doctrine-dbal/en/latest/reference/configuration.html#connecting-using-a-url
# IMPORTANT: You MUST configure your server version, either here or in config/packages/doctrine.yaml
#
# DATABASE_URL="sqlite:///%kernel.project_dir%/var/data.db"
DATABASE_URL="mysql://root:@127.0.0.1:3306/symf5?serverVersion=mariadb-10.4.11"
# DATABASE_URL="postgresql://symfony:[email protected]:5432/app?serverVersion=13&charset=utf8"
###< doctrine/doctrine-bundle ###
在这里,我的 .env.test 文件中有以下代码:
# define your env variables for the test env here
KERNEL_CLASS='App\Kernel'
APP_SECRET='$ecretf0rt3st'
SYMFONY_DEPRECATIONS_HELPER=999999
PANTHER_APP_ENV=panther
PANTHER_ERROR_SCREENSHOT_DIR=./var/error-screenshots
我不知道出了什么问题,我尝试了不同的方法,但都不起作用,我也不知道这出了什么问题,该怎么办。希望你们能帮我解决我的问题。 谢谢!
您有两个选择:
when@test:
doctrine:
dbal:
# "TEST_TOKEN" is typically set by ParaTest
dbname_suffix: '_test%env(default::TEST_TOKEN)%'
我想你可能忘记创建 .env.test 文件。
在文档中,您可以阅读需要此文件:
https://symfony.com/doc/current/testing.html#customizing-environment-variables
在此文件中,您将使用正确的数据库进行测试。
告诉我它是否有效!
你的 phpunit.xml 看起来怎么样,或者你有吗?
我们在项目目录中添加了一个 phpunit.xml 并在 phpunit.xml 文件中声明了必要的环境变量,例如:
<?xml version="1.0" encoding="UTF-8"?>
<phpunit xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:noNamespaceSchemaLocation="vendor/phpunit/phpunit/phpunit.xsd"
colors="true"
bootstrap="vendor/autoload.php"
cacheResultFile=".phpunit.cache/test-results"
executionOrder="depends,defects"
forceCoversAnnotation="true"
beStrictAboutCoversAnnotation="true"
beStrictAboutOutputDuringTests="true"
beStrictAboutTodoAnnotatedTests="true"
convertDeprecationsToExceptions="true"
failOnRisky="true"
failOnWarning="true"
verbose="true"
>
<php>
<ini name="display_errors" value="1" />
<ini name="error_reporting" value="1" />
<env name="APP_ENV" value="test" force="true" />
<env name="KERNEL_CLASS" value="App\Kernel" />
<env name="APP_DEBUG" value="false" />
<env name="DATABASE_URL" value="sqlite:///:memory:" force="true" />
<var name="DB_DBNAME" value="app" />
</php>
<testsuites>
<testsuite name="Test Suite">
<directory>tests</directory>
</testsuite>
</testsuites>
<coverage cacheDirectory=".phpunit.cache/code-coverage" processUncoveredFiles="true">
<include>
<directory suffix=".php">src</directory>
</include>
<exclude>
<directory>src/Entity</directory>
<directory>src/Repository</directory>
<file>src/Kernel.php</file>
</exclude>
</coverage>
<listeners>
<listener class="Symfony\Bridge\Phpunit\SymfonyTestsListener" />
</listeners>
<extensions>
<extension class="Symfony\Component\Panther\ServerExtension" />
</extensions>
</phpunit>
为了设置所有功能测试,我们在tests/Framework/FunctionalTestCase.php 上初始化数据库模式
<?php
namespace App\Tests\Framework;
use App\Tests\Framework\DatabaseUtil\InitDatabase;
use Doctrine\ORM\EntityManagerInterface;
use Symfony\Bundle\FrameworkBundle\KernelBrowser;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
class FunctionalTestCase extends WebTestCase
{
protected EntityManagerInterface|null $entityManager = null;
private KernelBrowser|null $client = null;
protected function setUp(): void
{
parent::setUp();
self::ensureKernelShutdown();
$this->client = static::createClient();
InitDatabase::updateSchema($this->client);
$this->entityManager = $this->client->getContainer()
->get('doctrine')
->getManager();
}
protected function getClientFromParent(): KernelBrowser
{
return $this->client;
}
}
以及测试/Framework/DatabaseUtil/InitDataBase.php:
<?php
namespace App\Tests\Framework\DatabaseUtil;
use Doctrine\ORM\Tools\SchemaTool;
class InitDatabase
{
public static function updateSchema(object $kernel): void
{
$entityManager = $kernel->getContainer()->get('doctrine.orm.entity_manager');
$metaData = $entityManager->getMetadataFactory()->getAllMetadata();
$schemaTool = new SchemaTool($entityManager);
$schemaTool->updateSchema($metaData);
}
}
我们在 ControllerTests 中使用这个FunctionalTestCase,例如:
<?php
namespace App\Tests\Controller\AnyController;
use App\Tests\Framework\FunctionalTestCase;
use App\Entity\User;
use App\TestsDataFixture\UserFixture;
use Doctrine\Common\Collections\Collection;
use Doctrine\DBAL\Exception\TableNotFoundException;
use Doctrine\Persistence\ObjectManager;
class AnyControllerTest extends FunctionalTestCase
{
private User $user;
private User $entityUser;
private KernelBrowser $client;
public function setUp(): void
{
parent::setUp();
$userFixture = new UserFixture();
$this->user = $userFixture->load($this->entityManager);
$this->entityUser = $this->entityManager->getRepository(User::class)->findAll()[0];
$this->client = $this->getClientFromParent();
}
public function tearDown(): void
{
parent::tearDown();
$this->delete([$this->entityUser], $this->entityManager);
}
public function testLoginSuccessful(): void
{
$payload = [
'username' => $this->user->getEmail(),
'password' => $this->user->getPassword()
];
$this->client->loginUser($this->user);
$this->client->request(
'POST',
'/auth/login',
[],
[],
[
'Content-Type' => 'application/json'
],
json_encode($payload)
);
$response = $this->client->getResponse()->getContent();
$data = json_decode($response, true);
$this->assertResponseIsSuccessful();
$this->assertIsString($data['token']);
}
private function deleteFromDatabase(array|Collection $entities, ObjectManager $manager): void
{
$connection = $manager->getConnection();
$databasePlatform = $connection->getDatabasePlatform();
if ($databasePlatform->supportsForeignKeyConstraints()) {
$connection->query('SET FOREIGN_KEY_CHECKS=0');
}
foreach($entities as $entity) {
try {
$query = $databasePlatform->getTruncateTableSQL(
$manager->getClassMetadata(get_class($entity))->getTableName()
);
$connection->executeUpdate($query);
} catch(TableNotFoundException $exception) {
// do nothing
}
}
if ($databasePlatform->supportsForeignKeyConstraints()) {
$connection->query('SET FOREIGN_KEY_CHECKS=1');
}
}
}
UserFixture 是一个普通的 DataFixture,具有用于生成 FakeUser 的加载方法,如下例所示:https://symfony.com/bundles/DoctrineFixturesBundle/current/index.html
您可以将私有删除方法放入特征中,以便在多个控制器中使用。
在此示例中,我们使用内存中的 sqlite 数据库,但您也可以将 phpunit 中的 DATABASE_URL 更改为 MariaDB DSN。