使用 Mockery 时 Laravel 测试用例异常

问题描述 投票:0回答:0

User
型号

class User extends Authenticatable
{
    use HasApiTokens, HasFactory, Notifiable;

    const TYPE_MERCHANT = 'merchant';
    const TYPE_AFFILIATE = 'affiliate';

    /**
     * The attributes that are mass assignable.
     *
     * @var array<int, string>
     */
    protected $fillable = [
        'name',
        'email',
        'password',
        'type'
    ];

    /**
     * The attributes that should be hidden for serialization.
     *
     * @var array<int, string>
     */
    protected $hidden = [
        'password',
        'remember_token',
    ];

    /**
     * The attributes that should be cast.
     *
     * @var array<string, string>
     */
    protected $casts = [
        'email_verified_at' => 'datetime',
    ];

    public function merchant(): HasOne
    {
        return $this->hasOne(Merchant::class);
    }

    public function affiliate(): HasOne
    {
        return $this->hasOne(Affiliate::class);
    }
}

Merchant
型号

class Merchant extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'domain',
        'display_name',
        'turn_customers_into_affiliates',
        'default_commission_rate'
    ];

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }

    public function orders(): HasMany
    {
        return $this->hasMany(Order::class);
    }
}

Affiliate
型号

class Affiliate extends Model
{
    use HasFactory;

    protected $fillable = [
        'user_id',
        'merchant_id',
        'commission_rate',
        'discount_code'
    ];

    public function merchant()
    {
        return $this->belongsTo(Merchant::class);
    }

    public function user()
    {
        return $this->belongsTo(User::class);
    }

    public function orders()
    {
        return $this->hasMany(Order::class);
    }
}

Order
型号

class Order extends Model
{
    use HasFactory;

    const STATUS_UNPAID = 'unpaid';
    const STATUS_PAID = 'paid';

    protected $fillable = [
        'external_order_id',
        'merchant_id',
        'affiliate_id',
        'subtotal',
        'commission_owed',
        'payout_status',
        'customer_email',
        'created_at'
    ];

    public function merchant()
    {
        return $this->belongsTo(Merchant::class);
    }

    public function affiliate()
    {
        return $this->belongsTo(Affiliate::class);
    }
}

这是我想要通过的测试用例,我们根本无法修改测试用例,这不是选择。

这是我已经实施的解决方案,但我无法通过测试,并且收到以下错误:

Mockery\Exception\BadMethodCallException : Received Mockery_3_App_Models_Affiliate::getAttribute(), but no expectations were specified
 /Users/mac/Downloads/testProject/vendor/laravel/framework/src/Illuminate/Database/Eloquent/Model.php:2222
 /Users/mac/Downloads/testProject/app/Services/OrderService.php:43
 /Users/mac/Downloads/testProject/tests/Feature/Services/OrderServiceTest.php:59
class OrderService
{
    public function __construct(
        protected AffiliateService $affiliateService,
        protected  ApiService $apiService
    ) {}

    /**
     * Process an order and log any commissions.
     * This should create a new affiliate if the customer_email is not already associated with one.
     * This method should also ignore duplicates based on order_id.
     *
     * @param  array{order_id: string, subtotal_price: float, merchant_domain: string, discount_code: string, customer_email: string, customer_name: string} $data
     * @return void
     */
    public function processOrder(array $data): void
    {
        if (!$this->getOrderByExternalOrderId($data['order_id'])) {
            $merchant = Merchant::where('domain', $data['merchant_domain'])->firstOrFail();
            $affiliate = Affiliate::where('user_id', function ($query) use ($data) {
                $query->select('id')
                    ->from('users')
                    ->where('email', $data['customer_email']);
            })
            ->first();

            if (!$affiliate) {
                $affiliate = $this->affiliateService->register($merchant, $data['customer_email'], $data['customer_name'], 0.1);
            }

            $order = new Order([
                'external_order_id' => $data['order_id'],
                'subtotal' => $data['subtotal_price'],
                'affiliate_id' => $affiliate->id,
                'merchant_id' => $merchant->id,
                'commission_owed' => $data['subtotal_price'] * $affiliate->commission_rate,
            ]);

            $order->save();
        }
    }

    public function getOrderByExternalOrderId($externalOrderId)
    {
        return Order::where('external_order_id', $externalOrderId)->first();
    }
}
laravel testing mockery
© www.soinside.com 2019 - 2024. All rights reserved.