Laravel单元测试:运行多个测试方法时重新定义错误

时间:2014-02-12 20:59:37

标签: php unit-testing laravel

我正在尝试在阅读需要活动数据库连接的示例here后运行一组单元测试。它似乎适用于一个单元测试,但由于重新定义了Laravel Command类中包含的常量,它将因多次测试而失败。以下是运行PHP单元后收到的错误:

PHPUnit 3.7.31 by Sebastian Bergmann.

FEE

Time: 203 ms, Memory: 5.00Mb

There were 2 errors:

1) MessageControllerTest::testSixMonths
ErrorException: Constant SHARE_SEND_EXPIRATION already defined

src/app/commands/DeleteExpiredSends.php:31
src/app/start/artisan.php:14
src/vendor/laravel/framework/src/Illuminate/Console/start.php:57
src/vendor/laravel/framework/src/Illuminate/Console/Application.php:30
src/vendor/laravel/framework/src/Illuminate/Foundation/Artisan.php:70
src/vendor/laravel/framework/src/Illuminate/Foundation/Artisan.php:45
src/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:206
src/app/tests/MessageControllerTest.php:46
src/app/tests/MessageControllerTest.php:46
src/app/tests/MessageControllerTest.php:21

2) MessageControllerTest::testOneYear
ErrorException: Constant SHARE_SEND_EXPIRATION already defined

src/app/commands/DeleteExpiredSends.php:31
src/app/start/artisan.php:14
src/vendor/laravel/framework/src/Illuminate/Console/start.php:57
src/vendor/laravel/framework/src/Illuminate/Console/Application.php:30
src/vendor/laravel/framework/src/Illuminate/Foundation/Artisan.php:70
src/vendor/laravel/framework/src/Illuminate/Foundation/Artisan.php:45
src/vendor/laravel/framework/src/Illuminate/Support/Facades/Facade.php:206
src/app/tests/MessageControllerTest.php:46
src/app/tests/MessageControllerTest.php:46
src/app/tests/MessageControllerTest.php:21

FAILURES!
Tests: 3, Assertions: 1, Errors: 2.

这是我的单元测试:

<?php

class MessageControllerTest extends TestCase
{
    /**
     * setUp() : set up the unit tests by initializing the database
     */
    public function setUp()
    {
        // call the parent's setup method
        parent::setUp();

        // init the DB
        $this->migrateDatabase();
    }

    /**
     * createApplication() : bootstrap the app in order to execute
     * tests
     *
     * @return Symfony\Component\HttpKernel\HttpKernelInterface  
     */
    public function createApplication()
    {
        // set the unitTesting flag to true
        $unitTesting = true;

        // set the environment variable to 'testing'
        $testEnvironment = 'testing';

        return require __DIR__.'/../../bootstrap/start.php';
    }

    /**
     * migrateDatabase() : load the sqlite database into memory
     */
    private function migrateDatabase()
    {
        Artisan::call('migrate');
    }

    /**
     * testHundredFilesMessage() : tests to see if custom message will
     * return after 100 messages have been sent by the same user
     */
    public function testHundredFilesMessage()
    {
        // TODO
        $this->assertTrue(false);
    }

    /**
     * testSixMonthMessage() : test the six months message
     */
    public function testSixMonthMessage()
    {
        // TODO
        $this->assertTrue(false);
    }

    /**
     * testOneYearMessage() : test the one-year message
     */
    public function testOneYearMessage()
    {
        // TODO
        $this->assertTrue(false);
    }
}

第一个测试似乎通过,但所有后续测试都会抛出错误。我猜不知怎样多次调用createApplication()方法,这可能解释了CommandDeleteExpiredSends被重新定义的原因;该类在其构造函数中显示define语句:

/**
 * Create a new command instance.
 *
 * @return void
 */
public function __construct()
{
    parent::__construct();
    define("SHARE_SEND_EXPIRATION", 14);
}

如果有人能告诉我如何避免重新定义此单元测试,以避免修改Command类的内部,那将是最有帮助的。这个单元测试似乎只是一个问题。

3 个答案:

答案 0 :(得分:2)

对于每个测试方法,为phpunit添加两个注释,如下所示:

/* @runInSeparateProcess
 * @preserveGlobalState disabled
 */
public function testPageShow()
{
  • runInSeparateProcess :在单独的过程中运行每个测试
  • preserveGlobalState已停用 :禁用先前测试的全局状态

答案 1 :(得分:1)

我认为暂时解决方案虽然您仍然不确定放置这些全局常量的位置,但请改用defined

defined('SAMPLE_GLOBAL_CONSTANT')
  or define('SAMPLE_GLOBAL_CONSTANT', 'sample value of the constant')

顺便说一下,如果你还运行全局函数的重定义异常,你也可以使用function_exists方法。

但请务必使用Class来保存全局函数,以便轻松测试应用程序。就像把它放在像Helper这样的东西上,或者像StringHelper那样更具体。

答案 2 :(得分:0)

使用SenseException的解决方案删除所有define语句(事实证明在整个应用程序中只使用了两个),而使用类常量确实解决了问题。