php - 想测试 laravel 中某个工厂创建的特定方法的调用
问题描述
我正在尝试编写一个执行类似操作的集成测试。
ModelClass::factory([$params])
使用而不是构造函数在测试的 setUp 方法中创建类的实例在这个类上调用一些导致各种事情发生的方法
事件将在某个时候被触发
侦听事件,事件侦听器将调用产生事件的同一对象上的方法。
究竟哪个方法将被调用(和参数)取决于类内部的一些逻辑(这主要是我想要测试的)。
方法本身没有做任何事情(目前),但我想知道它被调用了。功能可能会在将来的某个时候由其他人由子类实现。
所以我想断言这个方法在测试过程中的某个时候被调用,并测试哪些参数被传递给它。目前我已经设法模拟出事件本身以检查它是否被触发,但我只能测试该方法是否被手动调用(通过将 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;
}
解决方案
欢迎来到嘲讽的欢乐世界,愿我成为你的向导。您想模拟调用并从那里获取,问题是依赖注入和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();
}
}
这是在我的本地项目上测试的,所以你应该设置为实现类似的东西。
推荐阅读
- javascript - python flask javascript DELETE 405(不允许的方法)
- c - 分支和链接上的同步异常
- r - 无法将使用 R 3.x 创建的 ggplot2 对象绘制到从 RDS 文件导入的 R 4.x 中
- jenkins - jenkins如何强制下游项目只建一次?
- arduino - Arduino GPS 时间和坐标值更新问题
- r - R中是否有计算多个多边形面积的函数?
- google-cloud-platform - Stackdriver 自定义提醒
- php - 未设置 Cookie,但它们出现在 PHP 标头中
- python - 使用 random.sample 将字符串替换为字典中的值
- r - 我们可以用 R 中的新字段填充列吗?