【问题标题】:CakePHP 3 - Unit Test tearDown() failing to remove file: 'resource temporarily unavailable'CakePHP 3 - 单元测试 tearDown() 无法删除文件:'资源暂时不可用'
【发布时间】:2019-12-16 03:52:01
【问题描述】:

在我的应用程序中,用户可以上传文件,其他用户可以下载它们。作为控制器集成测试的一部分,我将几个测试文件移动到上传目录中,以便测试下载操作。

移动setUp() 中的文件并在teardown() 中删除它们是有效的,只要我不接触测试中的文件。当测试返回文件时,tearDown() 无法删除它们,我收到错误消息:

警告错误:取消链接(C:\xampp\htdocs\2deal\keys_test\1_open.key):资源暂时不可用

我该如何解决这个问题?

  • 我尝试打开和关闭tearDown() 中的文件,但没有效果。有趣的是,fopen() 函数成功了,所以文件实际上并没有被锁定。
  • 我还发现了这个similar question,解决方案是使用文件删除对象。所以我在tearDown() 的顶部添加了unset($this->_response);,但再次无济于事。
  • 我尝试添加sleep(10); 添加tearDown() 的开头,这也没有任何区别。所以这不是时间问题。

整个测试文件如下所示:

    /**
     * setUp method before each test
     */
    public function setUp()
    {
        Configure::write('Keys.path', 'keys_test');

        // Config writing must happen before parent::setUp()
        parent::setUp();

        $files = [
            '1_open.key',
            '1_close.key',
            '2_open.key',
            '2_close.key'
        ];
        foreach ($files as $file)
        {
            copy(self::SOURCE_DIR . $file, ROOT . DS . Configure::read('Keys.path') . DS . $file);
        }
    }

    /**
     * tearDown method after each test
     */
    public function tearDown()
    {
        parent::tearDown();

        // Clear test upload directory
        $files = glob(ROOT . DS . Configure::read('Keys.path') . DS . '*');

        foreach ($files as $file)
        {

            if (is_file($file))
            {
                \unlink($file); // Delete file
            }
        }
    }

    /**
     * Test getFile method
     * 
     * @return void
     */
    public function testGetFile()
    {
        $this->get('/carkeys/get-file/1/open.json');

        $file = $this->_response->getFile();

        $real_file = self::SOURCE_DIR . '1_open.key';

        $this->assertResponseOk();
        $this->assertFileEquals($file->path, $real_file);
    }

【问题讨论】:

    标签: cakephp phpunit cakephp-3.0 unlink


    【解决方案1】:

    文件未锁定,但有一个打开的句柄。

    从 CakePHP 3.4 开始,响应使用流作为响应主体。它在附加正文内容或文件时创建流,并立即打开流以进行写入或读取。

    长话短说,在尝试删除文件之前关闭流:

    $this->_response->getBody()->close();
    

    【讨论】:

    • 我不知道你是怎么做到的@ndm,再一次:点对点!问题:为什么在标准parent::tearDown() 中不会发生这种情况?
    • @Roberto 没有人真正想过我猜...适合IntegrationTestTrait::cleanup(),PR 可能会受到欢迎 :)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-08-18
    • 2021-02-21
    相关资源
    最近更新 更多