在CodeIgniter 4/PHP中运行多个测试时无法从MockSession中清除旧错误

llycmphe  于 2022-12-07  发布在  PHP
关注(0)|答案(1)|浏览(89)

我正在使用Codeigniter 4框架,我有一个控制器函数,它显示一个带有姓名、电子邮件和消息字段的表单,然后在提交时验证输入。我正在尝试使用此控制器的内置PHPUnit测试套件设置2个测试用例:一个有所有错误,一个没有错误。问题是,在我运行了有错误的第一个测试之后,第二个测试总是失败,并保存了相同的错误。我已经尝试过销毁会话,但由于测试套件使用MockSession,destroy()的工作方式似乎不一样。
以下是显示表单的函数:

public function question()
{
    $items = array(
        "name"          => array("display" => "Your Name", "type" => "input"),
        "email"         => array("display" => "Your Email", "type" => "input"),
        "message"       => array("display" => "Message", "type" => "textarea", "rows" => 5),
    );

    $data = $this->getForm($items, array(), "How Can We Help?");
    $this->displayView("template/form", $data);
}

以下是表单提交后验证输入、向用户显示消息并重定向回表单的函数:

public function attemptQuestion()
{
    $rules = array(
        "name"          => array(
            "rules" => "required|string|max_length[30]",
            "errors" => array(
                "required" => "Your name is required",
                "max_length" => "Please limit to the first 30 characters in your name"
            )
        ),
        "email"         => array(
            "rules" => "required|valid_email|max_length[30]",
            "errors" => array(
                "required" => "Your email is required",
                "valid_email" => "Your email is invalid",
                "max_length" => "Email address is limited to 30 characters"
            )
        ),
        "message"           => array(
            "rules" => "required",
            "errors" => array(
                "required" => "Message is required"
            )
        ),
    );

    if (! $this->validate($rules))
    {
        return redirect()->to(site_url("contact/question"))->withInput()->with("errors", $this->validator->getErrors());
    }
    return redirect()->to(site_url("contact/question"))->with("message", lang("Base.messageSent"));
}

下面是测试类:

namespace CodeIgniter;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\DatabaseTestTrait;
use CodeIgniter\Test\FilterTestTrait;
use CodeIgniter\Test\FeatureTestTrait;

class QuestionTest extends CIUnitTestCase
{
    use FilterTestTrait;

    public function testQuestionError()
    {
        $params = array(
            "name" => "01234567890123456789012345678901234567", // >30 characters
            "email" => "01234567890123456789012345678901234567", // >30 characters, invalid email
            "message" => NULL, // empty
            csrf_token() => csrf_hash()
        );

        $errors = array(
            'name' => 'Please limit to the first 100 characters in your name',
            'email' => 'Your email is invalid',
            'message' => 'Message is required'
        );

        $this->checkIndex($params, $errors);
    }

    public function testQuestionSuccess()
    {
        $params = array(
            "name" => "Joe Tester",
            "email" => "joe@example.com",
            "message" => "this is a test",
            csrf_token() => csrf_hash()
        );

        $this->checkIndex($params, FALSE, lang("Base.messageSent"));
    }

    private function checkQuestion($parameters, $errors = FALSE, $message = FALSE)
    {
        // clear session
        $_SESSION = [];

        $result = $this->post("contact/index", $parameters);

        $result->assertOK();

        $result->assertRedirect();

        $result->assertRedirectTo(site_url("contact/question"));

        if ($errors)
        {
            $result->assertSessionHas('errors', $errors);
        }
        if ($message)
        {
            $result->assertSessionHas('message', $message);
        }
    }
}

这里有几个相关的链接供参考,但似乎仍然不能完全回答这个问题:
https://github.com/codeigniter4/CodeIgniter4/issues/3578
https://forum.codeigniter.com/thread-74701.html

更新

我已经升级到了CI4.2.0,默认情况下启用“resetServices”,这应该可以解决这个问题,但是不幸的是,我得到了同样的错误。作为参考,我尝试将$this-〉post调用 Package 在print语句中,如下所示:

file_put_contents('php://stderr', print_r($parameters, true));
        $result = $this->post("contact/index", $parameters);
        print_r($_SESSION);

这将产生以下结果:

evana@LAPTOP-ICCPFR27 MINGW64 /c/sites/www (master)
$ ./vendor/bin/phpunit --filter 'ContactPostTest'
PHPUnit 9.5.20 #StandWithUkraine

Warning:       No code coverage driver available

Array
(
    [name] => 01234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789
    [email] => 01234567890123456789012345678901234567890123456789012345678901234567890123456789089@example.com
    [subject] =>
    [csrfPEtoken] => 928d217bb8d905caa5783275a72347db
)
.Array
(
    [_ci_old_input] => Array
        (
            [get] => Array
                (
                )

            [post] => Array
                (
                )

        )

    [__ci_vars] => Array
        (
            [_ci_old_input] => new
            [_ci_validation_errors] => new
            [errors] => new
        )

    [_ci_validation_errors] => a:6:{s:4:"name";s:53:"Please limit to the first 100 characters in your name";s:5:"email";s:21:"Your email is invalid";s:7:"message";s:19:"Message is required";}
    [errors] => Array
        (
            [name] => Please limit to the first 100 characters in your name
            [email] => Your email is invalid
            [message] => Message is required
        )

)
Array
(
    [name] => Evan
    [email] => evan@example.com
    [message] => this is a test
    [csrfPEtoken] => a55091ab0a922566c44b3ede325b59cd
)
F                                                                  2 / 2 (100%)Array
(
    [_ci_old_input] => Array
        (
            [get] => Array
                (
                )

            [post] => Array
                (
                )

        )

    [__ci_vars] => Array
        (
            [_ci_old_input] => new
            [_ci_validation_errors] => new
            [errors] => new
        )

    [_ci_validation_errors] => a:6:{s:4:"name";s:53:"Please limit to the first 100 characters in your name";s:5:"email";s:21:"Your email is invalid";s:7:"message";s:19:"Message is required";}
    [errors] => Array
        (
            [name] => Please limit to the first 100 characters in your name
            [email] => Your email is invalid
            [message] => Message is required
        )

)

Time: 00:00.320, Memory: 16.00 MB

There was 1 failure:

1) CodeIgniter\ContactPostTest::testQuestionSuccess
'message' is not in the current $_SESSION
Failed asserting that an array has the key 'message'.

C:\sites\www\vendor\codeigniter4\framework\system\Test\TestResponse.php:255
C:\sites\www\tests\app\Controllers\ContactPostTest.php:101
C:\sites\www\tests\app\Controllers\ContactPostTest.php:67

FAILURES!
Tests: 2, Assertions: 7, Failures: 1.
hc2pp10m

hc2pp10m1#

为了清除会话,您需要使用MockSession并启用resetServices。此外,为了防止对其他人有帮助,您需要在每个函数中只包含一个HTTP请求(当我扩展测试时,我将所有错误调用放在一个函数中,这也导致了会话问题)。
下面是更正后的代码:

<?php

namespace CodeIgniter;

use CodeIgniter\Test\CIUnitTestCase;
use CodeIgniter\Test\FilterTestTrait;
use CodeIgniter\Test\FeatureTestTrait;
use CodeIgniter\Session\Handlers\ArrayHandler;
use CodeIgniter\Test\Mock\MockSession;
use Config\Services;

class ContactPostTest extends CIUnitTestCase
{
    use FilterTestTrait, FeatureTestTrait;

    protected $setUpMethods = [
        'resetServices',
        'mockSession',
    ];

    public function testQuestionError()
    {
        $params = array(
            "name" => "01234567890123456789012345678901234567", // >30 characters
            "email" => "01234567890123456789012345678901234567", // >30 characters, invalid email
            "message" => NULL, // empty
            csrf_token() => csrf_hash()
        );

        $errors = array(
            'name' => 'Please limit to the first 100 characters in your name',
            'email' => 'Your email is invalid',
            'message' => 'Message is required'
        );

        $this->checkQuestion($params, $errors);
    }

    public function testQuestionSuccess()
    {
        $params = array(
            "name" => "Joe Tester",
            "email" => "joe@example.com",
            "message" => "this is a test",
            csrf_token() => csrf_hash()
        );

        $this->checkQuestion($params, FALSE, lang("Base.messageSent"));
    }

    private function checkQuestion($parameters, $errors = FALSE, $message = FALSE)
    {
        $result = $this->post("contact", $parameters);

        $result->assertOK();

        $result->assertRedirect();

        $result->assertRedirectTo(site_url("contact"));

        if ($errors)
        {
            $result->assertSessionHas('errors', $errors);
        }
        if ($message)
        {
            $result->assertSessionHas('message', $message);
        }
    }
}

相关问题