PHPUnit 问题断言模拟是使用 Laravel 的 ReflectionProperty 对象

Posted

技术标签:

【中文标题】PHPUnit 问题断言模拟是使用 Laravel 的 ReflectionProperty 对象【英文标题】:PHPUnit issue asserting mock is a ReflectionProperty object using Laravel 【发布时间】:2015-11-06 18:40:05 【问题描述】:

我是 phpUnit 的新手,正在尝试设置我的第一个测试。它失败并显示以下错误消息

无法断言 ReflectionProperty Object (...) 是“Illuminate\Database\Eloquent\Model”类的实例。

本质上,我试图模拟一个模型的创建,我将其注入构造函数并通过反射测试它是正确的类型。我正在遵循这篇文章/答案中提出的建议:

How do I test this class using phpunit?

如果有人能给我一些指导,那将不胜感激。

正在测试的类在这里:

<?php

namespace PlaneSaleing\Repo\Listing;

use Illuminate\Database\Eloquent\Model;

class EloquentListing implements ListingInterface 

    protected $advert;

    public function __construct(Model $advert)
    
        $this->advert = $advert;
    

    /**
     * Get paginated listings
     *
     * @param int  Current page
     * @param int Number of listings per page
     * @return StdClass object with $items and $totalItems for pagination
     */
    public function byPage($page=1, $limit=10)
    

        $result = new \StdClass;
        $result->page = $page;
        $result->limit = $limit;
        $result->totalItems = 0;
        $result->items = array();

        $listings = $this->advert
                         ->orderBy('created_at')
                         ->skip( $limit * ($page-1) )
                         ->take($limit)
                         ->get();

        // Create object to return data useful for pagination
        $result->items = $listings->all();
        $result->totalItems = $this->totalListings();

        return $result;

    

服务商在这里:

<?php

namespace PlaneSaleing\Repo;

use Illuminate\Support\ServiceProvider;
use PlaneSaleing\Repo\Listing\EloquentListing as Listing;
use \Advert;

class RepoServiceProvider extends ServiceProvider 

    public function register()
    

      $this->app->bind('PlaneSaleing\Repo\Listing\ListingInterface', function($app) 
        $app->make(Listing(new Advert));
       );

    


我的测试在这里:

<?php

use \Mockery;
use \ReflectionClass;
use PlaneSaleing\Repo\Listing\EloquentListing;

class EloquentListingTest extends \TestCase


    /**
     * Testing if __constructor is setting up property
     */
    public function testModelSetsUp()
    
        $mock1 = Mockery::mock(Illuminate\Database\Eloquent\Model::class);

        $listing = new EloquentListing($mock1);

        $reflection = new ReflectionClass($listing);

        // Making your attribute accessible
        $property1 = $reflection->getProperty('advert');
        $property1->setAccessible(true);

        $this->assertInstanceOf(Illuminate\Database\Eloquent\Model::class, $property1);
    

【问题讨论】:

【参考方案1】:

断言时,应该使用反射属性的实际值,而不是属性本身:

public function testModelSetsUp()

    $mock1 = Mockery::mock(Illuminate\Database\Eloquent\Model::class);

    $listing = new EloquentListing($mock1);

    $reflection = new ReflectionClass($listing);

    // Making your attribute accessible
    $property1 = $reflection->getProperty('advert');
    $property1->setAccessible(true);

    $this->assertInstanceOf(
        Illuminate\Database\Eloquent\Model::class, 
        $property1->getValue($listing)
    );

但是,您可以大大简化测试:

public function testModelSetsUp()

    $mock1 = Mockery::mock(Illuminate\Database\Eloquent\Model::class);

    $listing = new EloquentListing($mock1);

    $this->assertAttributeInstanceOf(
        Illuminate\Database\Eloquent\Model::class, 
        'advert', 
        $listing
    );

更好的是,您可以使用有意义的变量名称,使用有意义的测试方法名称,而不仅仅是断言$advert 属性是Illuminate\Database\Eloquent\Model 的一个实例,而实际上是相同 实例传递给构造函数:

public function testConstructorSetsAdvert()

    $advert = Mockery::mock(Illuminate\Database\Eloquent\Model::class);

    $listing = new EloquentListing($advert);

    $this->assertAttributeSame(
        $advert,
        'advert',
        $listing
    );

【讨论】:

以上是关于PHPUnit 问题断言模拟是使用 Laravel 的 ReflectionProperty 对象的主要内容,如果未能解决你的问题,请参考以下文章

PHPUnit 方法调用期望与断言

如何在 Codeception 功能测试中使用 PHPUnit 断言方法?

如何用 phpunit 模拟 Laravel Eloquent 模型?

Laravel / PHPUnit:运行测试时没有模拟类

Laravel phpunit 模拟模型第一个函数

如何在 PHPUnit / Laravel 中模拟 JSON 文件