如何通过Laravel 5.4中的“创建”事件来测试是否调用了Eloquent模型方法?

时间:2017-07-11 13:22:44

标签: php laravel testing eloquent mockery

我想测试在触发eloquent event时是否调用方法。

在下面的示例中,当学生实例保存到学生实例时,我想通过 isApproved()方法自动设置已批准的属性数据库。

以下是学生模型类:

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Student extends Model
{

    public $guarded = [];


    protected static function boot()
    {
        parent::boot();

        // set approved attribute if its value is NULL
        self::creating(function (self $student) {
            $student->approved = $student->approved ?? $student->isApproved();
        });
    }

    /**
     * @return bool
     */
    public function isApproved()
    {
        return ($this->age >= 14) && ($this->age <= 20);
    }
}

为实现这一点,我在学生类的创建事件上添加了一个回调函数。

我正在尝试使用以下测试来测试 isApproved()方法调用:

<?php

namespace Tests\Feature;

use App\Student;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class StudentTest extends TestCase
{

    use DatabaseMigrations;

    /**
     * @test
     */
    public function student_is_auto_approved_on_save()
    {

        $mock = \Mockery::mock(Student::class);
        $mock->shouldReceive('isApproved')->once();

        Student::create([
            'name' => 'John Doe',
            'age' => 14
        ]);
    }
}

但测试未通过,显示以下转储

    PHPUnit 5.7.21 by Sebastian Bergmann and contributors.

E                                                                   1 / 1 (100%)

Time: 246 ms, Memory: 16.00MB

There was 1 error:

1) Tests\Feature\StudentTest::student_is_auto_approved_on_save
Mockery\Exception\InvalidCountException: Method isApproved() from Mockery_0_App_Student should be called
 exactly 1 times but called 0 times.

/students/vendor/mockery/mockery/library/Mockery/CountValidator/Exact.php:37
/students/vendor/mockery/mockery/library/Mockery/Expectation.php:298
/students/vendor/mockery/mockery/library/Mockery/ExpectationDirector.php:120
/students/vendor/mockery/mockery/library/Mockery/Container.php:297
/students/vendor/mockery/mockery/library/Mockery/Container.php:282
/students/vendor/mockery/mockery/library/Mockery.php:152
/students/vendor/laravel/framework/src/Illuminate/Foundation/Testing/TestCase.php:144
/home/user/.composer/vendor/phpunit/phpunit/src/TextUI/Command.php:186
/home/user/.composer/vendor/phpunit/phpunit/src/TextUI/Command.php:116

ERRORS!
Tests: 1, Assertions: 0, Errors: 1.

我做错了什么?

1 个答案:

答案 0 :(得分:0)

尝试

<?php

namespace Tests\Feature;

use App\Student;
use Tests\TestCase;
use Illuminate\Foundation\Testing\DatabaseMigrations;

class StudentTest extends TestCase
{
    use DatabaseMigrations;

    /**
     * @test
     * @dataProvider providerAutoApprovedAge
     * 
     * @param int $age
     */
    public function student_is_auto_approved_on_save($age)
    {
        $student = Student::create([
            'name' => 'John Doe' . $age,
            'age' => $age,
        ]);

        $student->save();

        $this->assertTrue($student->approved);
    }

    public function providerAutoApprovedAge()
    {
        for ($age = 14; $age <= 20; $age++) {
            yield [
                $age,
            ];
        }
    }

    /**
     * @test
     * @dataProvider providerNotAutoApprovedAge
     * 
     * @param int $age
     */
    public function student_is_not_auto_approved_on_save($age)
    {
        $student = Student::create([
            'name' => 'John Doe' . $age,
            'age' => $age,
        ]);

        $student->save();

        $this->assertFalse($student->approved);
    }

    public function providerNotAutoApprovedAge()
    {
        for ($age = 0; $age < 14; $age++) {
            yield [
                $age,
            ];
        }

        for ($age = 21; $age < 120; $age++) {
            yield [
                $age,
            ];
        }
    }
}

你可能想断言学生是

  • 自动批准在规定年龄范围内的年龄
  • 未自动批准超出规定年龄范围的年龄

您可以使用数据提供程序。

或者,你可以这样删除方法:

class StudentStub extends Student
{
    public $hasApprovedBeenInvoked = false;

    public function isApproved()
    {
        $this->hasApprovedBeenInvoked = true;
    }
}

class StudentTest extends TestCase
{
    use DatabaseMigrations;

    /**
     * @test
     */
    public function student_is_auto_approved_on_save($age)
    {
        $student = StudentStub::create([
            'name' => 'John Doe' . $age,
            'age' => $age,
        ]);

        $student->save();

        $this->assertTrue($student->hasApprovedBeenInvoked);
    }
}

但是,这仅在Student::create()使用后期静态绑定并返回StutentStub的实例时才有效。

而且大多数情况下,你不想嘲笑被测系统,但是如果你有任何合作者的话。在这里,没有任何。

供参考,见