handlers.rs 的 delete_user 部分:
let res = sqlx::query(
r#"
DELETE FROM users
WHERE id = $1 AND id = $2
"#,
)
.bind(id)
.bind(caller_id)
.execute(&pool)
.await
.map_err(|e| internal_err(e))?;
在 integration_tests.rs,將登入測試移到 PUT 前方添加並取得 jwt ,在測試 PUT 和 DELETE 時使用 jwt
#[tokio::test]
async fn integration_create_get_update_delete_user_flow() {
// ...
// POST /users/login -> 成功
let res = client
.post(format!("{}/users/login", base_url))
.json(&serde_json::json!({
"username_or_email": "user1",
"password": "password"
}))
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
let login_body: Value = res.json().await.unwrap();
let jwt = login_body
.get("access_token")
.and_then(|v| v.as_str())
.expect("login response should contain string field `access_token`");
// PUT /users/{id} - 成功
let res = client
.put(format!("{}/users/{}", base_url, id))
.bearer_auth(jwt)
.json(&serde_json::json!({"username": "new_user1"}))
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::OK);
// DELETE /users/{id} -> 成功
let res = client
.delete(format!("{}/users/{}", base_url, id))
.bearer_auth(jwt)
.send()
.await
.unwrap();
assert_eq!(res.status(), StatusCode::NO_CONTENT);
// ...
}
建立一個針對 Rust 專案的 CI 工作流程,在 push 與 pull_request 時自動跑測試,包含與外部服務(Postgres、Redis)的整合測試場景。
把以下內容放到 .github/workflows/ci.yml:
name: CI
# 在 push 與 pull_request 時觸發
on:
push:
branches: ["**"]
pull_request:
branches: ["**"]
env:
# 測試用 Postgres 帳號(與 services.db.env 保持一致)
POSTGRES_USER: myapp
POSTGRES_PASSWORD: myapp_pass
POSTGRES_DB: myapp_db
jobs:
test:
name: Run tests
runs-on: ubuntu-latest
services:
# Postgres service 用於測試(對應你的 tests spawn_app 使用)
postgres:
image: postgres:18
env:
POSTGRES_USER: ${{ env.POSTGRES_USER }}
POSTGRES_PASSWORD: ${{ env.POSTGRES_PASSWORD }}
POSTGRES_DB: ${{ env.POSTGRES_DB }}
ports:
- 5432:5432
options: >-
--health-cmd "pg_isready -U $${POSTGRES_USER} -d $${POSTGRES_DB}"
--health-interval 5s
--health-timeout 5s
--health-retries 10
# Redis service
redis:
image: redis:8
ports:
- 6379:6379
options: >-
--health-cmd "redis-cli ping"
--health-interval 5s
--health-timeout 5s
--health-retries 5
steps:
- name: Checkout
uses: actions/checkout@v4
- name: Set up Rust
uses: dtolnay/gh-actions-rust@stable
with:
toolchain: stable
profile: minimal
- name: Cache cargo registry and index
uses: actions/cache@v4
with:
path: |
~/.cargo/registry
~/.cargo/git
target
key: ${{ runner.os }}-cargo-${{ hashFiles('**/Cargo.lock') }}
restore-keys: |
${{ runner.os }}-cargo-
- name: Wait for Postgres to be ready
# Sleep a bit to allow DB initialization; pg_isready run in service but give extra buffer
run: sleep 5
- name: Export test env vars
run: |
echo "TEST_DATABASE_URL_BASE=postgresql://${POSTGRES_USER}:${POSTGRES_PASSWORD}@localhost:5432" >> $GITHUB_ENV
echo "TEST_REDIS_URL=redis://127.0.0.1:6379/" >> $GITHUB_ENV
- name: Install system deps for tests (libssl for sqlx)
run: sudo apt-get update && sudo apt-get install -y libssl-dev pkg-config
- name: Run cargo test
env:
# cargo test 期間可用到 DB 與 REDIS env(spawn_app 會用 TEST_DATABASE_URL_BASE)
TEST_DATABASE_URL_BASE: ${{ env.TEST_DATABASE_URL_BASE }}
TEST_REDIS_URL: ${{ env.TEST_REDIS_URL }}
RUST_LOG: info
run: cargo test --workspace --verbose --all-features
將程式碼 push 到 GitHub 後,一開始會是黃燈,經過一些時間後,黃燈將轉變成跟下面一樣的綠色勾勾。