package service import ( "context" "testing" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/internal/dto" "git.lzcwy.cn/zhengchiliu/zt-closet-backend/pkg/errcode" "github.com/DATA-DOG/go-sqlmock" ) // TestRefundApplyMarksOrderRefunding 申请退款受理成功:返回待处理退款流水信息,订单 2 -> 6 由 DAO 事务内完成。 func TestRefundApplyMarksOrderRefunding(t *testing.T) { mock := setupOrderQuotaTest(t) mock.ExpectQuery("SELECT .* FROM `orders` WHERE order_no = \\?"). WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "user_id", "order_status", "pay_amount", "pay_channel"}). AddRow(8, "ORDER-1", 7, 2, 990, 1)) mock.ExpectBegin() mock.ExpectQuery("SELECT .* FROM `orders` .*FOR UPDATE"). WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "user_id", "order_status", "pay_amount"}). AddRow(8, "ORDER-1", 7, 2, 990)) mock.ExpectQuery("SELECT .* FROM `refund_flow_logs`"). WillReturnRows(sqlmock.NewRows([]string{"id"})) mock.ExpectExec("INSERT INTO `refund_flow_logs`").WillReturnResult(sqlmock.NewResult(1, 1)) mock.ExpectExec("UPDATE `orders` SET").WillReturnResult(sqlmock.NewResult(0, 1)) mock.ExpectCommit() resp, e := NewOrderService().RefundApply(context.Background(), 7, &dto.RefundApplyRequest{OrderNo: "ORDER-1", Reason: "不想要了"}) if e != nil { t.Fatalf("unexpected error: %v", e) } if resp == nil || resp.RefundAmount != 990 || resp.Status != RefundStatusPending || resp.RefundNo == "" { t.Fatalf("unexpected response: %+v", resp) } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } // TestRefundApplyRejectsRepeatApply 重复/并发申请被 DAO 拒绝时映射为「当前状态不允许退款」。 func TestRefundApplyRejectsRepeatApply(t *testing.T) { mock := setupOrderQuotaTest(t) mock.ExpectQuery("SELECT .* FROM `orders` WHERE order_no = \\?"). WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "user_id", "order_status", "pay_amount", "pay_channel"}). AddRow(8, "ORDER-1", 7, 2, 990, 1)) // 行锁内读到订单已被并发请求置为 6 申请退款中:拒绝且不产生任何写入。 mock.ExpectBegin() mock.ExpectQuery("SELECT .* FROM `orders` .*FOR UPDATE"). WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "user_id", "order_status"}). AddRow(8, "ORDER-1", 7, OrderStatusRefunding)) mock.ExpectCommit() resp, e := NewOrderService().RefundApply(context.Background(), 7, &dto.RefundApplyRequest{OrderNo: "ORDER-1", Reason: "重复申请"}) if resp != nil || e != errcode.RefundNotAllowed { t.Fatalf("resp=%v err=%v, want RefundNotAllowed", resp, e) } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } // TestRefundApplyRejectsIOSVirtualOrder iOS 虚拟支付订单不走本接口,引导用户走 App Store。 func TestRefundApplyRejectsIOSVirtualOrder(t *testing.T) { mock := setupOrderQuotaTest(t) mock.ExpectQuery("SELECT .* FROM `orders` WHERE order_no = \\?"). WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "user_id", "order_status", "pay_amount", "pay_channel", "xpay_platform"}). AddRow(8, "ORDER-1", 7, 2, 990, 2, "ios")) resp, e := NewOrderService().RefundApply(context.Background(), 7, &dto.RefundApplyRequest{OrderNo: "ORDER-1", Reason: "不想要了"}) if resp != nil || e != errcode.IOSRefundViaAppStore { t.Fatalf("resp=%v err=%v, want IOSRefundViaAppStore", resp, e) } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } } // TestRefundApplyRejectsOtherUserOrder 非本人订单不允许申请退款(归属校验先于状态校验)。 func TestRefundApplyRejectsOtherUserOrder(t *testing.T) { mock := setupOrderQuotaTest(t) mock.ExpectQuery("SELECT .* FROM `orders` WHERE order_no = \\?"). WillReturnRows(sqlmock.NewRows([]string{"id", "order_no", "user_id", "order_status", "pay_amount", "pay_channel"}). AddRow(8, "ORDER-1", 9, 2, 990, 1)) resp, e := NewOrderService().RefundApply(context.Background(), 7, &dto.RefundApplyRequest{OrderNo: "ORDER-1", Reason: "越权申请"}) if resp != nil || e != errcode.Forbidden { t.Fatalf("resp=%v err=%v, want Forbidden", resp, e) } if err := mock.ExpectationsWereMet(); err != nil { t.Fatal(err) } }