简体   繁体   English

测试数据库 laravel 7.x 出现问题

[英]Problem with testing database laravel 7.x

I am trying to do unit testing in laravel 7.x.我正在尝试在 laravel 7.x 中进行单元测试。

I created a testing database which is identic to the database I use for my website.我创建了一个测试数据库,它与我用于我的网站的数据库相同。

I modified the phpunit.xml file, I created a .env.testing file and I added a "testing" connection to the database.php file but I am getting an "SQLSTATE[42S02]: Base table or view not found: 1146 Table 'cbs_perform_test.cbs_defis' doesn't exist (SQL: select count(*) as aggregate from cbs_defis )" error. I modified the phpunit.xml file, I created a .env.testing file and I added a "testing" connection to the database.php file but I am getting an "SQLSTATE[42S02]: Base table or view not found: 1146 Table 'cbs_perform_test.cbs_defis' 不存在(SQL: select count(*) as aggregate from cbs_defis )"错误。

I already checked multiple times the name of the database and the table to be sure I am using the correct one.我已经多次检查了数据库和表的名称,以确保我使用的是正确的。

I already followed these guides: Use different database for testing and local ;我已经遵循了这些指南: 使用不同的数据库进行测试和本地 How to Specify a Separate Database for Unit Testing on Laravel 5 如何为 Laravel 上的单元测试指定单独的数据库 5

Here is my 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"
         bootstrap="vendor/autoload.php"
         colors="true">
    <testsuites>
        <testsuite name="Unit">
            <directory suffix="Test.php">./tests/Unit</directory>
        </testsuite>
        <testsuite name="Feature">
            <directory suffix="Test.php">./tests/Feature</directory>
        </testsuite>
    </testsuites>
    <filter>
        <whitelist processUncoveredFilesFromWhitelist="true">
            <directory suffix=".php">./app</directory>
        </whitelist>
    </filter>
    <php>
        <server name="APP_ENV" value="testing"/>
        <server name="BCRYPT_ROUNDS" value="4"/>
        <server name="CACHE_DRIVER" value="array"/>
        <server name="DB_CONNECTION" value="testing"/>
        <server name="DB_DATABASE" value="cbs_perform_test"/>
        <server name="MAIL_MAILER" value="array"/>
        <server name="QUEUE_CONNECTION" value="sync"/>
        <server name="SESSION_DRIVER" value="array"/>
        <env name="DB_CONNECTION" value="testing"/>
    </php>

My database.php connection我的数据库。php 连接

'testing' => [
            'driver' => 'mysql',
            'url' => env('DATABASE_URL'),
            'host' => env('DB_HOST', '127.0.0.1'),
            'port' => env('DB_PORT', '3306'),
            'database' => env('DB_DATABASE', 'forge'),
            'username' => env('DB_USERNAME', 'forge'),
            'password' => env('DB_PASSWORD', ''),
            'unix_socket' => env('DB_SOCKET', ''),
            'charset' => 'utf8mb4',
            'collation' => 'utf8mb4_unicode_ci',
            'prefix' => '',
            'prefix_indexes' => true,
            'strict' => false,
            'engine' => null,
            'options' => extension_loaded('pdo_mysql') ? array_filter([
                PDO::MYSQL_ATTR_SSL_CA => env('MYSQL_ATTR_SSL_CA'),
            ]) : [],
        ],

my .env.testing file我的.env.testing文件

APP_ENV=testing

DB_CONNECTION=testing
DB_HOST=127.0.0.1
DB_PORT=3306
DB_DATABASE=cbs_perform_test
DB_USERNAME=root
DB_PASSWORD=

My test code我的测试代码

class DefiTest extends TestCase
{
    use DatabaseMigrations;
    use DatabaseTransactions;

    /**
     * A basic unit test example.
     *
     * @return void
     */
    public function testCreateDefi()
    {
        $request = new Request();
        $request->DEF_NOM = 'test';
        $request->DEF_DESCRIPTION = 'testdescriptio ajhsg ln';
        $request->DEF_NBSEMAINES = 2;
        $request->DEF_CONSEILS = 'jhasnciu launh sl';
        $request->DEF_VISIBLE = 1;
        $request->DEF_DATE_VISIBLE = Carbon::now()->toDate();
        $request->COA_ID = 3;

        $dfc = new DefiCoachController();
        $response = $dfc->createDefiTest($request);

        $this->assertDatabaseHas('cbs_defis', $request->all());
    }
}

The command I use for testing: php artisan test --env=testing我用于测试的命令:php artisan test --env=testing

First of all, hope I can help you fix your problem as I am pretty sure it is a silly mistake you are making somewhere in the connection.首先,希望我能帮助您解决问题,因为我很确定您在连接的某个地方犯了一个愚蠢的错误。

So, here are some tips:所以,这里有一些提示:

Do not test your code "invoking" core framework code...不要测试你的代码“调用”核心框架代码......

Instead of doing (unit testing):而不是做(单元测试):

$request = new Request();
$request->DEF_NOM = 'test';
$request->DEF_DESCRIPTION = 'testdescriptio ajhsg ln';
$request->DEF_NBSEMAINES = 2;
$request->DEF_CONSEILS = 'jhasnciu launh sl';
$request->DEF_VISIBLE = 1;
$request->DEF_DATE_VISIBLE = Carbon::now()->toDate();
$request->COA_ID = 3;

$dfc = new DefiCoachController();
$response = $dfc->createDefiTest($request);

$this->assertDatabaseHas('cbs_defis', $request->all());

Do (feature test):做(功能测试):

$data = [
    'nom' => 'test',
    'description' => 'testdescriptio ajhsg ln',
    'nbsemaines' => 2,
    'conseils' => 'jhasnciu launh sl',
    'visible' => 1,
    'date_visible' => Carbon::now()->toDate(),
    'coa_id' => 3,
];

$response = $this->post('your_desired_url_for_this_action', $data); // This can be get, post, put or delete

$this->assertDatabaseHas('cbs_defis', $data);

This way, you can make sure that:这样,您可以确保:

  1. Your URL is the one you want, without any typo or any errors您的 URL 是您想要的,没有任何错字或任何错误
  2. The controller is doing what it is supposed to do, inserting data in this case. controller 正在做它应该做的事情,在这种情况下插入数据。
  3. The controller is inserting the data you want it to insert. controller 正在插入您希望它插入的数据。 Let's say you have some processing behind curtains, here you can make sure that you sent "1 and 3" and it inserted "role X" (it is an example, let's say that would be your desired result after processing 1 and 3, so you are not directly inserting 1 and 3 )假设你在窗帘后面有一些处理,在这里你可以确保你发送了“1和3”并插入了“角色X”(这是一个例子,假设这将是你在处理1和3之后想要的结果,所以你不是直接插入1 and 3
  4. always avoid asserting data from where you are testing it.始终避免从您正在测试的地方断言数据。 In your case, you are using Request object, let's say it is your custom class, and you do something when you do $request->attribute1 = 2 , so when you read it back as $request->attribute1 maybe you have done some process to store it and you have modified it... if you are asserting that without explicitly saying assert that attribute1 is what I expect you are never asserting it.在您的情况下,您正在使用Request object,假设它是您的自定义 class,并且您在执行$request->attribute1 = 2时做了一些事情,所以当您将其读回$request->attribute1时,您可能已经做了一些存储它的过程并且你已经修改了它......如果你断言没有明确说assert that attribute1 is what I expect的你永远不会断言它。 If you have a mistake in your code and instead of returning b ( 1 = a , 2 = b , etc.) the code will always pass, because you have stored it as something else than expected, but you are asserting for what it has done (let's say that your mistake returned c instead of b ) so you are saying "find $request->attribute1 in the database" and you will have stored c instead of b (your expected value) and it will still find it and pass the test.如果您的代码有错误,而不是返回b1 = a2 = b等),代码将始终通过,因为您将其存储为超出预期的其他内容,但您正在断言它有什么完成(假设您的错误返回c而不是b )所以您说“在数据库中查找$request->attribute1 ”并且您将存储c而不是b (您的期望值)它仍然会找到并通过考试。

There is no need to create a new connection if it is the same except for DB_DATABASE or similar.如果除了DB_DATABASE或类似之外相同,则无需创建新connection In that case, you just define that info in .env.testing or in your phpunit.xml .在这种情况下,您只需在.env.testingphpunit.xml中定义该信息。

Also, no need to do <server name="DB_CONNECTION" value="testing"/> and <env name="DB_CONNECTION" value="testing"/> .此外,无需执行<server name="DB_CONNECTION" value="testing"/><env name="DB_CONNECTION" value="testing"/> If you see Laravel GitHub's phpunit.xml , you will see that they changed <env> to <server> on 5.7+, so stick to the one that corresponds to your version.如果你看到 Laravel GitHub 的phpunit.xml ,你会看到他们在 5.7+ 上将<env>更改为<server>对应的那个,所以坚持使用There is a difference though that I cannot remember now, but for testing, there is no problem.虽然我现在不记得有区别,但是对于测试,没有问题。


So, make sure you have set the right DB_HOST , DB_PORT , DB_USERNAME and DB_PASSWORD .因此,请确保您设置了正确的DB_HOSTDB_PORTDB_USERNAMEDB_PASSWORD You could have the same host but different port, or you could have same host and port but different database name, but same username and password.您可以拥有相同的主机但不同的端口,或者您可以拥有相同的主机和端口但不同的数据库名称,但相同的用户名和密码。 So make sure you are connecting to the correct database.因此,请确保您连接到正确的数据库。

As your error is that it cannot find the desired table, clearly you are connecting to a database, so username and password should not be your problem, but the table does not exist.由于您的错误是找不到所需的表,显然您正在连接到数据库,因此用户名和密码不应该是您的问题,但该表不存在。


One last important thing, are you using any trait on your tests?最后一件重要的事情,您是否在测试中使用了任何特征? There are some traits to automatically migrate the database and roll it back when finished, so there is no need for you to have your migrations sync manually in the testing environment.有一些特征可以自动迁移数据库并在完成后将其回滚,因此您无需在测试环境中手动同步迁移。 You should be using use RefreshDatabase;您应该使用use RefreshDatabase; trait to do so.这样做的特质。


Last tip, try to avoid doing DEF_SOMETHING because:最后一个提示,尽量避免做DEF_SOMETHING因为:

  1. If your controller is related to Defi , there is no need to say "this is DEF data", we already know, so you can directly do something .如果你的 controller 和Defi相关,就不用说“这是 DEF 数据”了,我们已经知道了,你可以直接something Same for database, if table name is cars , avoid doing car_wheels , car_doors , etc., do wheels , doors , etc.数据库也一样,如果表名是cars ,避免做car_wheelscar_doors等,做wheelsdoors等。
  2. Avoid doing X_Y , prefer to do x_y , same for database.避免做x_y X_Y对于数据库也是如此。 Stick to lowercase always and, for database, stick to snake_case , but for models' attributes, always stick to camelCase .始终坚持使用小写,对于数据库,坚持使用snake_case ,但对于模型的属性,始终坚持使用camelCase ( more info about cases) (有关案例的更多信息

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM