【问题标题】:Proper testing flow with Laravel?使用 Laravel 进行正确的测试流程?
【发布时间】:2016-01-04 23:28:44
【问题描述】:

我正在使用 Laravel 为 IOS 应用程序构建 API。我在使用 PHPUnit 和内置的 Laravel 测试测试 Web 应用程序时遇到了重大问题。

我的流程是 1. 用户有帐户 2. 用户需要经过身份验证才能执行任何操作。

假设我有一组用户,并且一个用户(所有者)可以管理属于其组之一的成员。我想测试用户将其他成员添加到他们的组的能力。

我有一个名为 testAddGroupMemberPass() 的测试方法应该

  1. 创建用户(所有者)
  2. 创建组并分配所有者
  3. 创建要添加到组的用户
  4. 断言所有者有权添加该成员。

    public function testAddGroupMemberPass()
    {
        // 1. create owner
        $owner = factory(User::class)->create();
        $token = JWTAuth::fromUser($owner);
    
        // 2. create group and attach user
        $group = new Group;
        $group->owner_id = $owner->id;
        $group->save();
    
        // 3. create the member to be
        $user = factory(User::class)->create();
    
        // 4. attempt attach the member to the group
        $this->edit('/groups/' . $group->id . '/add-member/' . $user->username . '?token=' . $token)
        ->seeJson(['success' => true]);
    }
    

要断言所有者可以添加用户,您必须首先创建所有者,然后创建组,然后创建要添加到组的用户,最后您才能尝试发出请求到 API 以实际添加该用户。

问题在于,在前 3 个步骤中可能会遇到与将成员添加到组的过程完全无关的各种问题,例如用户名和电子邮件唯一性约束。

那么我目前的方法有什么问题?我一直被告知测试应该完全相互独立,因此尝试使用以前的测试 AFAIK 生成的用户和组是没有意义的。

【问题讨论】:

    标签: php unit-testing laravel testing integration-testing


    【解决方案1】:

    您可以将123 抽象为一个基本测试类,并为测试这些特定功能的测试使用相同的方法。

    例如:

    // TestCase.php
    protected function createOwner()
    {
        return factory(User::class)->create();
    }
    
    protected function createGroup($owner)
    {
        // You didn't show this as a factory, but I figured you might want that
        $group = factory(Group::class)->create();
        $group->owner()->associate($owner);
        $group->save();
    
        return $group;
    }
    
    protected function createUser()
    {
        return factory(User::class)->create();
    }
    
    // In the file you mention above (should be extending TestCase.php)
    public function testAddGroupMemberPass()
    {
        // 1. create owner
        $owner = $this->createOwner();
        $token = JWTAuth::fromUser($owner);
    
        // 2. create group and attach user
        $group = $this->createGroup($owner);
    
        // 3. create the member to be
        $user = $this->createUser();
    
        // 4. attempt attach the member to the group
        $this->edit('/groups/' . $group->id . '/add-member/' . $user->username . '?token=' . $token)
             ->seeJson(['success' => true]);
    }
    

    这些方法可以用于其他测试,如下所示:

    // In UserTest.php (also extends TestCase.php)
    public function testItCreatesAUser()
    {
        $user = $this->createUser();
    
        $this->seeInDatabase('users', $user);
    }
    

    事实是,如果您需要您的世界以某种方式呈现,并且您正在进行某种功能或集成测试,那么您需要在某处封装该逻辑。将其移至基类将有助于删除重复的功能。

    【讨论】:

    • 这仍然会导致相同的问题,尽管由于随机生成的用户使用工厂而违反了约束。使用工厂生成的用户可能不是唯一的,从而导致在持久创建它们时违反约束。这些组还有 20 种其他情况,在每种方法中,它们还将调用抽象函数,每个函数都会创建新的持久用户,但实际上并不确保它们是有效的。你知道我的意思?我可能解释得不好,看着它已经筋疲力尽了......
    • 在 Laravel 中,使用 Illuminate\Foundation\Testing\DatabaseTransactions 特征来处理它。在每个测试之后执行Rollbacklaravel.com/docs/5.1/…
    • 理想情况下这会起作用,并且是我最初的方法。然而,交易似乎发生在实际测试中。因此,当我使用包含在事务中的因素创建用户时。然后我们去创建组,它也被包裹在一个组中,等等......所以当我去附加所有者组时,他已经被交易清除,导致外键约束违规。
    • gist.github.com/kyle-mccarthy/… 这应该有助于进一步解释这个问题......我在 TestFile 中包含了 use DatabaseTransaction 特征,并且正在扩展 TestCase。
    • 我可以查看您的整个测试文件并发布TestCase.php吗?你使用的是哪个版本的 Laravel?它肯定会在每次测试后回滚。
    猜你喜欢
    • 2017-03-13
    • 1970-01-01
    • 1970-01-01
    • 2019-12-30
    • 2016-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多