You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Laravel 10 SQLite测试报错:YEAR/MONTH函数不存在,需用TestCase trait?

Laravel 10 测试时SQLite不支持YEAR/MONTH函数的解决办法

问题背景

我在Laravel 10的User模型中写了一个计算月度平均计算次数的方法,在应用视图里运行正常,但执行视图的assertStatus测试时报错。

模型方法代码:

public function numCalculationsAvgMonth(): string
{
    $data = NumberOfCalculations::where('user_id', $this->id)
        ->selectRaw('
            count(id) as data,
            YEAR(created_at) as year,
            MONTH(created_at) as month
        ')
        ->groupby('year', 'month')
        ->get()
        ->avg('data');

    return decimals($data, 2);
}

测试报错信息:

SQLSTATE[HY000]: General error: 1 no such function: YEAR (Connection: sqlite, SQL: select 
            count(id) as data,
            YEAR(created_at) as year,
            MONTH(created_at) as month
         from "number_of_calculations" where "user_id" = 1 group by "year", "month")

问题:是否需要在TestCase中使用trait来解决该问题?


解决思路与方案

报错本质是:应用运行用的是MySQL(或其他支持YEAR/MONTH函数的数据库),但测试环境用的是SQLite——SQLite原生没有这两个函数,所以测试时触发错误。不需要额外用trait,两种直接方案任选:

方案一:用Laravel兼容多数据库的查询语法

Laravel的查询构建器提供了适配不同数据库的语法支持,把原代码改成这样:

public function numCalculationsAvgMonth(): string
{
    $data = NumberOfCalculations::where('user_id', $this->id)
        ->selectRaw('count(id) as data')
        ->selectRaw('year(created_at) as year')
        ->selectRaw('month(created_at) as month')
        ->groupBy('year', 'month')
        ->get()
        ->avg('data');

    return decimals($data, 2);
}

Laravel会自动做语法转换:MySQL环境下用YEAR()/MONTH(),SQLite环境下自动换成strftime('%Y', created_at)/strftime('%m', created_at),完美兼容两种环境。

方案二:给SQLite注册自定义函数

如果不想修改模型代码,可以在测试用例的setUp方法里给SQLite注册YEAR和MONTH函数:

use Illuminate\Support\Facades\DB;

protected function setUp(): void
{
    parent::setUp();

    if (DB::connection()->getDriverName() === 'sqlite') {
        // 注册YEAR函数
        DB::getPdo()->sqliteCreateFunction('YEAR', function($date) {
            return date('Y', strtotime($date));
        });

        // 注册MONTH函数
        DB::getPdo()->sqliteCreateFunction('MONTH', function($date) {
            return date('m', strtotime($date));
        });
    }
}

这样SQLite就能识别这两个函数,原模型代码不需要改动,测试就能正常运行。


内容的提问来源于stack exchange,提问作者dgoma108

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.22 14:45:29