首页 > 解决方案 > 想测试 laravel 中某个工厂创建的特定方法的调用

问题描述

我正在尝试编写一个执行类似操作的集成测试。

所以我想断言这个方法在测试过程中的某个时候被调用,并测试哪些参数被传递给它。目前我已经设法模拟出事件本身以检查它是否被触发,但我只能测试该方法是否被手动调用(通过将 add()放入其中)。如果不模拟整个对象,我似乎找不到一种方法来做到这一点(这会破坏测试的目的,因为那时我只是在测试模拟)。

我知道你可以做“部分”模拟,也许这就是我需要的,但这似乎与::factory([$params])构造函数的风格不太匹配。

我将此作为答案包含在内,因为我无法编辑我的原件。

<?php
    // The test itself

    protected function setUp() : void
    {
        parent::setUp();
        $this->item = Item::factory()->createOne([
            "name" => "testing name",
            // Some other attributes
        ]);
    }

    public function test_the_thing() : void
    {
        $this->item->doSomeWork();
        $this->assertShouldHaveBeenCalled($item, "someMethod") // I want something like this
    }

    // Then a trait attached to the item class that looks like this

    public static function bootItemTrait(): void
    {
        Event::listen(function(MyCustomEvent $event) {
            if(method_exists($event->item,"someMethod") && some_other_conditions()) {
                $event->item->someMethod();
            }
        });
    }

    public function doSomeWork() : void {
        $result = doSomeComplicatedThings()
        MyCustomEvent::dispatch($this,$result);
    }

    // My custom event is just a basic event with this constructor

    public function __construct($item, $result)
    {
        $this->result = $result;
        $this->item = $item;
    }

标签: phplaraveltesting

解决方案


欢迎来到嘲讽的欢乐世界,愿我成为你的向导。您想模拟调用并从那里获取,问题是依赖注入和Laravel模拟模型并不容易,不推荐。

为了解决这个问题,请为您的调用创建一个包装器类,这将允许您覆盖Laravel容器中的包装器。所以你在哪里->doWork();。你可以做类似的事情。重要的是要知道,在使用依赖注入时,永远不要使用关键字new. 而是使用app(YourClass::class);,resolve(YourClass::class);或使用构造函数/句柄注入。在这种情况下,我使用这种resolve()方法。

class YourModel extends Model {

    public function doWork()
    {
        /** @var DoWorkService $doWorkService */
        $doWorkService = resolve(DoWorkService::class);

        $doWorkService->doWork(1, "2");
    }
}

在这个构思的例子中,我做了一个空壳来证明这一点。

namespace App\Services;

class DoWorkService
{
    public function doWork($param1, $param2) {
        throw new \Exception('This is mocked and should not be called');
    }
}

现在在您的测试课程中,您可以使用 Mocking 助手Laravel提供的功能。此示例要求doWork()方法调用一次,在这种情况下使用参数1, "2"和返回值。true

namespace Tests\Unit;

use App\Services\DoWorkService;
use Mockery\MockInterface;
use Tests\TestCase;

class DoWorkTest extends TestCase
{
    public function testDoWork()
    {
        $yourModel = // create your model with the factory;

        $mock = $this->mock(DoWorkService::class, function (MockInterface $mock) {
            $mock->shouldReceive('doWork')
                ->once()
                ->with(1, "2")
                ->andReturn(true);
        });

        $yourModel->doWork();
    }
}

这是在我的本地项目上测试的,所以你应该设置为实现类似的东西。


推荐阅读