【问题标题】:Have setup method run only once设置方法只运行一次
【发布时间】:2017-04-03 13:09:16
【问题描述】:

我有:

1. IntegrationTestCase extends TestCase  
2. UnitTestCase extends TestCase
3. AcceptanceTestCase extends TestCase  

在这些中,我有很多非静态方法,这些方法用于很多测试。我所有的测试类都扩展了这三个类之一。

现在在很多测试类中,我有一个setUp 方法,它可以准备所需的数据和服务并将它们分配给类变量:

class SomeTestClass extends IntegrationTestCase
{
    private $foo;

    public function setUp()
    {
        parent::setUp();

        $bar = $this->createBar(...);
        $this->foo = new Foo($bar);
    }

    public function testA() { $this->foo...; }  
    public function testB() { $this->foo...; }
}

问题是 setUp 运行每个测试都失败了我想要做的事情,如果 setUp 方法所做的事情需要很长时间,这将乘以测试方法的数量。

使用public function __construct(...) { parent::__construct(..); ... } 会产生问题,因为现在 Laravel 中的低级方法和类不可用。

【问题讨论】:

  • 在 setUp 方法中添加一些检查
  • setup() 的全部意义在于它应该为每个单元测试运行;因为每个单元测试都应该与任何其他单元测试完全隔离运行
  • 你看at了吗?但仍然想到马克贝克的评论..
  • @xmike 对我没有帮助,因为它是一种静态方法。
  • 但是单元测试不应该针对实际数据库运行;你应该嘲笑数据库

标签: php laravel phpunit


【解决方案1】:

对于遇到此问题的下一个人:

我有一个问题,我想在运行测试之前迁移数据库,但我不希望在每次测试后都迁移数据库,因为执行时间太长了。

我的解决方案是使用静态属性来检查数据库是否已经迁移:

class SolutionTest extends TestCase
{
    protected static $wasSetup = false;

    protected function setUp()
    {
        parent::setUp();

        if ( ! static::$wasSetup) {
            $this->artisan('doctrine:schema:drop', [
                '--force' => true
            ]);

            $this->artisan('doctrine:schema:create');

            static::$wasSetup = true;
        }
    }
}

【讨论】:

【解决方案2】:

Saman Hosseini 和类似者给出的解决方案对我没有用。使用静态属性标记为下一个测试类重置。

为了克服这个问题,我编写了单独的测试类来测试测试数据库连接并初始化测试数据库一次并确保它在所有其他测试之前运行

<?php

namespace Tests\Unit;

use Tests\TestCase;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Artisan;

/**
 * @runTestsInSeparateProcesses
 */
class DatabaseConnectionTest extends TestCase
{
    /**
     * Test the database connection
     *
     * @return void
     */
    public function testDatabaseConnection()
    {
        $pdo = DB::connection()->getPdo();
        $this->assertNotNull($pdo);
    }

    /**
     * Initialize the test database for once
     *
     * @return void
     */
    public function testInititializeTestDatabase()
    {
        Artisan::call('migrate:fresh');
        Artisan::call('db:seed');
    }
}

【讨论】:

    【解决方案3】:

    我不确定您看到的 setUpBeforeClass 的哪些问题是静态的,除了 Mark Ba​​ker 提到的问题。不过,我假设您确实知道自己在做什么。以下是可能的用法示例。

    class BeforeAllTest extends PHPUnit_Framework_TestCase
    {
        private static $staticService;
        private $service; // just to use $this is tests
    
        public static function setUpBeforeClass() {
            self::createService();
        }
    
        public static function createService(){
            self::$staticService = 'some service';
        }
    
        /**
         * just to use $this is tests
         */
        public function setUp(){
            $this->service = self::$staticService;
        }
    
        public function testService(){
            $this->assertSame('some service', $this->service);
        }
    }
    

    更新:您可以在https://phpunit.de/manual/current/en/database.html 看到一些类似的方法(搜索“提示:使用您自己的抽象数据库测试用例”)。我确信您已经在使用它,因为您正在进行密集的数据库测试。但是没有人限制这种方式仅用于 db-issues。

    UPDATE2:好吧,我猜你必须使用 self::createService 而不是 $this-&gt;createService 之类的东西(我已经更新了上面的代码)。

    【讨论】:

    • 好的,但我需要打电话给self::$staticService = $this-&gt;createService(..) 对我没有帮助。
    猜你喜欢
    • 1970-01-01
    • 2012-08-18
    • 2022-10-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多