【问题标题】:PhpUnit - mocking laravel model with relationsPhpUnit - 用关系模拟 laravel 模型
【发布时间】:2018-05-25 00:56:53
【问题描述】:

我正在尝试模拟(仅作为示例)$user->posts()->get()。

示例服务:

use App\Models\User;

class SomeClass{
    public function getActivePost(User $user): Collection
    {
        return $user->posts()->get();
    }
}

和我的模型: 和型号:

namespace App\Models;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\HasMany;
use \App\Models\Post;

class User extends Model
{
    public function posts() : HasMany
    {
        return $this->hasMany(Post::class);
    }
}

这不起作用:

$this->user = Mockery::mock(User::class);
$this->user
    ->shouldReceive('wallets->get')
    ->andReturn('test output');

错误: TypeError:Mockery_2_App_Models_User::posts() 的返回值必须是 Illuminate\Database\Eloquent\Relations\HasMany 的实例,返回的 Mockery_4__demeter_posts 的实例

没有返回类型提示(在 post() 方法上)一切正常。我必须修改 andReturn() 吗?不知道怎么做

【问题讨论】:

  • 该错误似乎与您的代码中的任何内容都不对应。

标签: laravel unit-testing eloquent phpunit


【解决方案1】:

可以通过使用具有有效类名的别名前缀来解决此错误。像下面这样:

$m = m::mock('alias:App\Models\User');

更多信息可以查看官方文档http://docs.mockery.io/en/latest/reference/creating_test_doubles.html#aliasing

【讨论】:

    【解决方案2】:

    您也可以这样使用。

    use App\Models\User;
    
    class SomeClass{
        public function getActivePost(User $user): Collection
        {
            $user->load('posts');
            return $user->posts;
        }
    }
    

    首先您需要模拟帖子,然后将其添加到 Collection(不要忘记在顶部 use 它)。然后,当您调用posts 属性时,它会模拟$posts。在这种情况下,它不会抛出关于返回类型的错误。

    use Illuminate\Database\Eloquent\Collection;
    
    
    $post = $this->mock(Post::class)->makePartial();
    $posts = new Collection([$post]);
    
    $this->user = Mockery::mock(User::class);
    $this->user
        ->shouldReceive('getAttribute')
        ->with('posts');
        ->andReturn($posts);
    

    【讨论】:

      【解决方案3】:

      我也不会在这里使用模拟。完全没有必要。所以我写的单元测试是:

      • 创建用户。
      • 创建一些用户创作的帖子。
      • 对用户和帖子执行断言。

      所以代码在我的测试中会是这样的:

      $user = factory(User::class)->create();
      $posts = factory(Post::class, 5)->create(['user_id' => $user->id]);
      
      $this->assertNotEmpty($user->id);
      $this->assertNotEmpty($posts);
      
      $this->assertEquals(5, $posts->fresh()->count());
      $this->assertEquals($user->id, $post->fresh()->first()->user_id);
      

      【讨论】:

        【解决方案4】:

        如果你想测试这种关系,你可以:

         /** @test */
        function user_has_many_posts()
        {
            $user = factory(User::class)->create();
            $post= factory(Post::class)->create(['user_id' => $user->id]);
        
            //Check if database has the post..
            $this->assertDatabaseHas('posts', [
                'id' => $post->id,
                'user_id' => $user->id,
            ]);
            //Check if relationship returns collection..
            $this->assertInstanceOf('\Illuminate\Database\Eloquent\Collection', $user->posts);
        
        }
        

        【讨论】:

        • 这不是问的,实际上是相反的:这里你实际上是通过关系创建一个Post实例,而问题要求嘲笑关系,即:没有真正的@ 987654323@ 实例,但 $user->posts()->get() 表现得好像它是一个。
        猜你喜欢
        • 2021-12-23
        • 2017-09-04
        • 2014-01-29
        • 2021-06-27
        • 2013-12-20
        • 2018-03-03
        • 2015-03-19
        • 2019-04-04
        相关资源
        最近更新 更多