当前位置: 首页 > 知识库问答 >
问题:

Laravel8-来自工厂关系模型的模拟方法

太叔炎彬
2023-03-14

我试图测试代码的特定部分,但模型类的某些依赖性使得此测试非常难以执行。如果这些依赖关系在注入的类上,我可以轻松地模拟该类。当来自工厂的数据库关系时,是否可以执行类似的操作?我正在将这个想法转化为Laravel文档中的示例,以便更容易举例说明:

use App\Models\Post;
use App\Models\User;

$user = User::factory()
            ->has(Post::factory()->count(3))
            ->create();

假设我正在测试一个控制器,它将为用户的帖子创建注释。我将使用一个html" target="_blank">工厂来创建用户和post,并对route/api/comments执行测试post调用,此post包含post_id(int)和comment(text)字段。但是,Comments控制器将调用Post::CanadComment()方法,该方法将执行大量验证以验证是否可以创建注释。所有这些验证都超出了我的测试范围。

是否可以使用Mock of the Post模型类,这样我就可以制作,例如:

$postMock->shouldReceive('canAddComment')->once()->andReturn(true);

所以我不需要创建一个完整的场景来进行测试?

可能的解决办法:

扩展Post类,仅用于测试:

class PostThatAlwaysAllowsComments extends Post
{
    public function canAddComment() {
        return true;
    }
}

然后在测试中:

use App\Models\Post;
use App\Models\User;

$user = User::factory()
            ->has(PostThatAlwaysAllowsComments::factory()->count(3))
            ->create();

共有1个答案

井兴怀
2023-03-14

Laravel中,嘲笑模型并不是真正的标准或既不方便。大多数时候,你安排数据,让我们模型做模型做的事情。在你的情况下,你可以利用一个包装器/代理aproach,让它能够模拟你的呼叫。这也将作为嘲笑的切入点,因为您需要容器中的一个类来被嘲笑。

class PostThatAlwaysAllowsComments extends Post
{
    public function canAddComment() {
        resolve(CommentService::class)->comment($this);
    }
}

由于new关键字将不起作用,因此使用resolve as从容器中获取服务。

现在使用Laravelsmock syntaxic sugar,您可以模拟底层服务,避免触发您不关心的代码并断言它实际上被调用。

namespace Tests\Unit;

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

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

        $mock = $this->mock(CommentService::class, function (MockInterface $mock) {
            $mock->shouldReceive('comment')
                ->once()
                ->andReturn(true);
        });

        // call api or method
    }
}
 类似资料:
  • 我的Laravel 5.2应用程序具有以下结构: 用户:id名称。。。 文章: id标题正文user_id(fk) 注释:id主体用户id(fk)发布id(fk) 我想创建几个用户(20个),为每个用户创建随机数量的帖子,并为每个帖子创建随机数量的评论(即使是固定数量也可以)。 我可以创建用户并为每个帖子分配帖子,但我不能为每个帖子分配评论:我有: 我发现了一些东西,但不起作用: 注意:我在模型之

  • 定义关联 关联在 Hyperf 模型类中以方法的形式呈现。如同 Hyperf 模型本身,关联也可以作为强大的 查询语句构造器 使用,提供了强大的链式调用和查询功能。例如,我们可以在 role 关联的链式调用中附加一个约束条件: $user->role()->where('level', 1)->get(); 一对一 一对一是最基本的关联关系。例如,一个 User 模型可能关联一个 Role 模型

  • 亦称: 虚拟构造函数、Virtual Constructor、Factory Method 意图 工厂方法模式是一种创建型设计模式, 其在父类中提供一个创建对象的方法, 允许子类决定实例化对象的类型。 问题 假设你正在开发一款物流管理应用。 最初版本只能处理卡车运输, 因此大部分代码都在位于名为 卡车的类中。 一段时间后, 这款应用变得极受欢迎。 你每天都能收到十几次来自海运公司的请求, 希望应用

  • 工厂方法模式是一种实现了「工厂」概念的面向对象设计模式。就像其他创建型模式一样,它也是处理在不指定对象具体类型的情况下创建对象的问题。工厂方法模式的实质是「定义一个创建对象的接口,但让实现这个接口的类来决定实例化哪个类。工厂方法让类的实例化推迟到子类中进行。」 var Humanity = (function() { function Man() { this.introduce = fu

  • 问题 直到开始运行你才知道需要的是什么种类的对象。 解决方案 使用 工厂方法(Factory Method) 模式和选择对象都是动态生成的。 你需要将一个文件加载到编辑器,但是直到用户选择文件时你才知道它的格式。一个类使用工厂方法 ( Factory Method ) 模式可以根据文件的扩展名提供不同的解析器。 class HTMLParser constructor: ->

  • 简介 “工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应