test: 后端自动化测试套件
Service 单元测试(SQLite in-memory): - auth: 登录成功/失败/禁用账号,token 刷新 - stock: 入库审核、出库审核(含库存不足)、单号生成 - license: 激活、设备绑定验证、过期检测 Handler 集成测试(httptest + SQLite): - auth: 登录 API 成功/401 场景 - product: CRUD 完整流程 + hotel_id 隔离验证 - stock_in: 创建→提交→审核完整流程 - stock_out: 完整流程 + 库存不足 400 - inventory: 库存查询/过滤/盘点创建 - warehouse: CRUD 覆盖率:service 90.4%,handler 56.1% 共 50 个测试用例,全部 PASS Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -0,0 +1,94 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/require"
|
||||
|
||||
"github.com/wangjia/jiu/backend/testutil"
|
||||
)
|
||||
|
||||
func TestWarehouseHandler_CRUD(t *testing.T) {
|
||||
db := testutil.SetupTestDB()
|
||||
hotel := testutil.CreateTestHotel(db, "WH001")
|
||||
user := testutil.CreateTestUser(db, hotel.ID, "admin", "pass", "admin")
|
||||
token := getAuthToken(user.ID, hotel.ID, "admin")
|
||||
r := setupProtectedRouter(db)
|
||||
|
||||
// 1. Create
|
||||
w := makeRequest(r, "POST", "/api/v1/warehouses", token, map[string]interface{}{
|
||||
"name": "Main Warehouse",
|
||||
"location": "Floor 1",
|
||||
})
|
||||
require.Equal(t, http.StatusCreated, w.Code)
|
||||
whID := extractID(w)
|
||||
assert.NotZero(t, whID)
|
||||
|
||||
// 2. List
|
||||
w = makeRequest(r, "GET", "/api/v1/warehouses", token, nil)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
resp := parseResponse(w)
|
||||
data := resp["data"].([]interface{})
|
||||
assert.Len(t, data, 1)
|
||||
|
||||
// 3. Update
|
||||
w = makeRequest(r, "PUT", fmt.Sprintf("/api/v1/warehouses/%d", whID), token, map[string]interface{}{
|
||||
"name": "Updated Warehouse",
|
||||
"location": "Floor 2",
|
||||
})
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
updatedData := parseResponse(w)["data"].(map[string]interface{})
|
||||
assert.Equal(t, "Updated Warehouse", updatedData["name"])
|
||||
|
||||
// 4. Delete
|
||||
w = makeRequest(r, "DELETE", fmt.Sprintf("/api/v1/warehouses/%d", whID), token, nil)
|
||||
assert.Equal(t, http.StatusOK, w.Code)
|
||||
|
||||
// 5. List after delete - should be empty
|
||||
w = makeRequest(r, "GET", "/api/v1/warehouses", token, nil)
|
||||
resp = parseResponse(w)
|
||||
data = resp["data"].([]interface{})
|
||||
assert.Len(t, data, 0)
|
||||
}
|
||||
|
||||
func TestWarehouseHandler_UpdateNotFound(t *testing.T) {
|
||||
db := testutil.SetupTestDB()
|
||||
hotel := testutil.CreateTestHotel(db, "WH002")
|
||||
user := testutil.CreateTestUser(db, hotel.ID, "admin", "pass", "admin")
|
||||
token := getAuthToken(user.ID, hotel.ID, "admin")
|
||||
r := setupProtectedRouter(db)
|
||||
|
||||
w := makeRequest(r, "PUT", "/api/v1/warehouses/99999", token, map[string]interface{}{
|
||||
"name": "Nonexistent",
|
||||
})
|
||||
assert.Equal(t, http.StatusNotFound, w.Code)
|
||||
}
|
||||
|
||||
func TestWarehouseHandler_HotelIsolation(t *testing.T) {
|
||||
db := testutil.SetupTestDB()
|
||||
|
||||
hotelA := testutil.CreateTestHotel(db, "WH_A")
|
||||
userA := testutil.CreateTestUser(db, hotelA.ID, "adminA", "pass", "admin")
|
||||
tokenA := getAuthToken(userA.ID, hotelA.ID, "admin")
|
||||
|
||||
hotelB := testutil.CreateTestHotel(db, "WH_B")
|
||||
userB := testutil.CreateTestUser(db, hotelB.ID, "adminB", "pass", "admin")
|
||||
tokenB := getAuthToken(userB.ID, hotelB.ID, "admin")
|
||||
|
||||
r := setupProtectedRouter(db)
|
||||
|
||||
// 酒店 A 创建仓库
|
||||
w := makeRequest(r, "POST", "/api/v1/warehouses", tokenA, map[string]interface{}{
|
||||
"name": "Hotel A Warehouse",
|
||||
})
|
||||
require.Equal(t, http.StatusCreated, w.Code)
|
||||
|
||||
// 酒店 B 看不到酒店 A 的仓库
|
||||
w = makeRequest(r, "GET", "/api/v1/warehouses", tokenB, nil)
|
||||
resp := parseResponse(w)
|
||||
data := resp["data"].([]interface{})
|
||||
assert.Len(t, data, 0)
|
||||
}
|
||||
Reference in New Issue
Block a user