Files
tamabox/internal/db/box_analytics_test.go
tamakyi c9b426acbb fix(insights): 数据面板「每日回答数」按 answered_at 分组,而非 created_at
BoxTrend 的回答那条 SQL 复用了 d.day(基于 created_at 的日期表达式)做 GROUP BY,
但 WHERE 过滤用的是 answered_at。于是「40 天前创建、昨天才回答」的提问被排除在
窗口外(created_at < from),昨天的回答数里不出现;「今天创建、明天回答」的又
被记到今天。趋势图里的「每日回答数」根本不是「某天被回答了多少」。

单独构造 answerDay(基于 COALESCE(answered_at, updated_at)),WHERE / GROUP BY /
SELECT 三者口径一致。PG 用 to_char(... AT TIME ZONE INTERVAL ...),MySQL 用
CONVERT_TZ,与 analyticsDialectFor 对 created_at 的处理对称。

新增 box_analytics_test.go:构造「40 天前创建、昨天回答」的提问,断言计入昨天,
并做变异验证(改回 d.day → 测试失败)。
2026-10-29 18:52:29 +08:00

76 lines
2.4 KiB
Go

// Copyright 2026 tamakyi. All rights reserved.
// Use of this source code is governed by a MIT-style
// license that can be found in the LICENSE file.
package db
import (
"context"
"testing"
"time"
"github.com/stretchr/testify/require"
)
// TestBoxTrendAnswerByAnsweredDate 验证「每日回答数」按 answered_at 分组,
// 而不是按 created_at。
//
// 背景:BoxTrend 一度两条 SQL 都复用 created_at 的日期表达式,导致「40 天前创建、
// 昨天才回答」的提问被排除在窗口外(created_at < from),昨天/今天的回答数里
// 根本不出现;「今天创建、明天回答」的又会被记到今天。本测试构造一条
// 「创建日远早于窗口、回答日落在窗口内」的提问,断言它出现在回答日那天。
func TestBoxTrendAnswerByAnsweredDate(t *testing.T) {
db, cleanup := newTestDB(t)
ctx := context.Background()
store := NewBoxAnalyticsStore(db)
t.Cleanup(func() {
_ = cleanup("questions")
})
now := time.Now()
// 窗口 = 最近 7 天
from := now.AddDate(0, 0, -6)
to := now
// 一条 40 天前创建、昨天才回答的提问
answeredAt := now.AddDate(0, 0, -1)
createdAt := now.AddDate(0, 0, -40)
q := &Question{
UserID: 9,
Content: "很久以前问的,昨天才回答",
Answer: "这是回答",
AnsweredAt: &answeredAt,
}
// 直接写 created_at / answered_at,绕过 Create 的自动时间戳
require.NoError(t, db.Model(&Question{}).Create(q).Error)
require.NoError(t, db.Model(&Question{}).Where("id = ?", q.ID).
Updates(map[string]interface{}{
"created_at": createdAt,
"answered_at": answeredAt,
"updated_at": answeredAt,
}).Error)
trend, err := store.BoxTrend(ctx, 9, from, to)
require.NoError(t, err)
// 找到回答日那天(昨天)的计数,答案数应 >= 1
var found bool
for _, d := range trend {
if d.Day.Year() == answeredAt.Year() &&
d.Day.Month() == answeredAt.Month() &&
d.Day.Day() == answeredAt.Day() {
require.GreaterOrEqual(t, d.Answers, int64(1),
"回答应计入 answered_at 那一天,而不是按 created_at 被排除")
found = true
}
// 创建日(40 天前)不应出现在窗口内
if d.Day.Year() == createdAt.Year() &&
d.Day.Month() == createdAt.Month() &&
d.Day.Day() == createdAt.Day() {
t.Errorf("创建日在窗口外,不应出现在趋势里")
}
}
require.True(t, found, "回答日应出现在趋势结果里")
}