CakePHP 3.6 控制器集成测试 - 未发送 HTTP 请求

Posted

技术标签:

【中文标题】CakePHP 3.6 控制器集成测试 - 未发送 HTTP 请求【英文标题】:CakePHP 3.6 Controller Integration Testing - HTTP requests not sent 【发布时间】:2019-05-31 09:40:32 【问题描述】:

我正在尝试使用 Cakephp 3.6 的测试工具实现控制器集成测试。我假设这将通过对正在运行的网络服务器发出“真实”(如在 CURL 中)HTTP 请求来处理,但看起来并非如此。下面是我正在使用的测试用例代码。

我遇到的问题:

    测试用例以某种方式设法访问控制器操作, 即使网络服务器根本没有运行(Apache 关闭并且没有 dev 网络服务器正在运行)。 运行此测试时,控制器无权访问 $_SERVER(见下文)和测试用例中定义的任何 $postData 在控制器端显示为空。 当我将exit; 放在控制器代码中时,整个测试用例 停止,这表明控制器代码是直接运行的,而不是 通过 HTTP 请求。

问题:除了使用 CURL 和手动处理请求之外,我如何在测试控制器时发出“真正的”HTTP 请求?

显然,我要么不了解控制器测试是如何完成的,要么我做错了什么。

我正在使用的测试用例:

/tests/TestCase/Controller/JobsControllerTest.php

<?php
namespace App\Test\TestCase\Controller;

use Cake\ORM\TableRegistry;
use Cake\TestSuite\IntegrationTestCase;

/**
 * App\Controller\JobsController Test Case
 */
class JobsControllerTest extends IntegrationTestCase


    /**
     * Test add method
     *
     * @return void
     */
    public function testAdd()
    
        $this->useHttpServer(true);

        $this->configRequest([
            'headers' => [
                'Content-Type' => 'application/json',
                'X-Api-Key' => '8f083c8f083c8f083c8f083c'
            ]
        ]);
        $postData = [
            'user_id' => 3,
            'job_status' => 'New'
        ];
        $this->post('/jobs/add', $postData);

        $this->assertResponseSuccess();
        $jobs = TableRegistry::get('Jobs');
        $query = $jobs->find()->where(['user_id' => $postData['user_id']]);
        $this->assertEquals(1, $query->count());
    


$_SERVER global 来自我正在测试的控制器的转储:

Array
(
    [LS_COLORS] => rs=0:di=01;34 [...]
    [LANG] => en_US.UTF-8
    [HOME] => /home/tomasz
    [TERM] => screen
    [PATH] => /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/snap/bin
    [MAIL] => /var/mail/root
    [LOGNAME] => root
    [USER] => root
    [USERNAME] => root
    [SHELL] => /bin/bash
    [SUDO_COMMAND] => vendor/bin/phpunit --verbose
    [SUDO_USER] => tomasz
    [SUDO_UID] => 1000
    [SUDO_GID] => 1000
    [PHP_SELF] => vendor/bin/phpunit
    [SCRIPT_NAME] => vendor/bin/phpunit
    [SCRIPT_FILENAME] => vendor/bin/phpunit
    [PATH_TRANSLATED] => vendor/bin/phpunit
    [DOCUMENT_ROOT] =>
    [REQUEST_TIME_FLOAT] => 1546631688.0758
    [REQUEST_TIME] => 1546631688
    [argv] => Array
        (
            [0] => vendor/bin/phpunit
            [1] => --verbose
        )

    [argc] => 2
)

【问题讨论】:

【参考方案1】:

CakePHP 集成测试不会发出实际的 HTTP 请求,它们会模拟它们,速度非常快,允许进行某些模拟、检查会话内容、访问异常详细信息等,所有这些事情实际上是不可能的(在至少不容易)在使用真正的 HTTP 请求时。如果您确实需要发出实际请求,那么您应该考虑使用其他实用程序,例如 Codeception(特别是验收测试)。

使用 CakePHP 时,建议您不要直接访问 PHP 超全局变量,而是从 CakePHP 提供的抽象 API 中检索数据!破坏集成测试是造成这种情况的原因之一。模拟请求将收到一个请求对象,该对象已使用您的测试用例中的数据准备好,您需要在此处查找它。

例如,如果您想在您的应用程序中访问 POST 数据,可能在您的控制器中,那么您可以这样做:

$user_id = $this->request->getData('user_id');

另见

Cookbook > Testing > Controller Integration Testing Cookbook > Request & Response Objects

【讨论】:

我可以发誓我已经检查了控制器上的请求对象并且它看起来是空的。阅读您的答案后再次检查,瞧! POST 数据在那里 :) 我肯定需要重构 $_SERVER。感谢您的回答 - 一如既往的完美!

以上是关于CakePHP 3.6 控制器集成测试 - 未发送 HTTP 请求的主要内容,如果未能解决你的问题,请参考以下文章

Cakephp auth 和 acl 未登录用户组

cakephp 3 中的控制器未运行

cakephp + phpunit + gitlab 持续集成

CakePHP4 Ajax:从控制器发送到视图

CakePHP 2.0:从模型或其控制器访问未关联的模型?

调用未定义的方法 Cake\ORM\Entity::query() CakePhp