From zenbu-powers
當在 Gherkin 測試中驗證操作成功或失敗時,參考此規範。 驗證 HTTP status code + error response body。
npx claudepluginhub zenbuapps/zenbu-powers --plugin zenbu-powersThis skill uses the workspace's default tool permissions.
驗證 HTTP operation 的結果狀態(成功 2xx / 失敗 4xx / 5xx),以及錯誤訊息。
Searches, retrieves, and installs Agent Skills from prompts.chat registry using MCP tools like search_skills and get_skill. Activates for finding skills, browsing catalogs, or extending Claude.
Checks Next.js compilation errors using a running Turbopack dev server after code edits. Fixes actionable issues before reporting complete. Replaces `next build`.
Guides code writing, review, and refactoring with Karpathy-inspired rules to avoid overcomplication, ensure simplicity, surgical changes, and verifiable success criteria.
Share bugs, ideas, or general feedback.
驗證 HTTP operation 的結果狀態(成功 2xx / 失敗 4xx / 5xx),以及錯誤訊息。
| 項目 | 技術 |
|---|---|
| Language | C# 12 / .NET 8+ |
| BDD | SpecFlow 3.9+ |
| HTTP | HttpResponseMessage |
| JSON | System.Text.Json |
| Assertion | FluentAssertions 6+ |
Then 語句驗證操作整體的成功或失敗結果,不涉及具體回傳資料。
識別規則:
這類 step 通常可以跨 feature 共用,放在 Steps/CommonThen/。
_ctx 取出 HttpResponseMessageStatusCode 屬於 2xx(成功)或 4xx(失敗)message / detail / errorusing System.Text.Json;
using FluentAssertions;
using TechTalk.SpecFlow;
namespace ProjectName.IntegrationTests.Steps.CommonThen;
[Binding]
public class SuccessSteps
{
private readonly ScenarioContext _ctx;
public SuccessSteps(ScenarioContext ctx) => _ctx = ctx;
}
[Binding]
public class FailureSteps
{
private readonly ScenarioContext _ctx;
public FailureSteps(ScenarioContext ctx) => _ctx = ctx;
}
[Then(@"操作成功")]
public void ThenOperationSucceeds()
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().BeInRange(200, 299,
"預期成功(2xx),實際 {0}", (int)response.StatusCode);
}
[Then(@"操作失敗")]
public void ThenOperationFails()
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().BeInRange(400, 499,
"預期失敗(4xx),實際 {0}", (int)response.StatusCode);
}
[Then(@"HTTP 狀態碼應為 (.*)")]
public void ThenStatusCodeShouldBe(int expectedCode)
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().Be(expectedCode);
}
[Then(@"錯誤訊息應包含 ""(.*)""")]
public async Task ThenErrorMessageContains(string expectedMessage)
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
var body = await response.Content.ReadAsStringAsync();
var message = ExtractErrorMessage(body);
message.Should().Contain(expectedMessage,
"預期錯誤訊息包含 '{0}',實際: {1}", expectedMessage, message);
}
private static string ExtractErrorMessage(string body)
{
try
{
var data = JsonSerializer.Deserialize<JsonElement>(body);
// ASP.NET Core ProblemDetails 標準:detail / title
// 一般自訂錯誤:message / error
if (data.TryGetProperty("detail", out var detail))
return detail.GetString() ?? body;
if (data.TryGetProperty("message", out var msg))
return msg.GetString() ?? body;
if (data.TryGetProperty("error", out var error))
return error.ValueKind == JsonValueKind.String
? error.GetString() ?? body
: error.ToString();
if (data.TryGetProperty("title", out var title))
return title.GetString() ?? body;
return body;
}
catch (JsonException)
{
return body;
}
}
[Then(@"錯誤代碼應為 ""(.*)""")]
public async Task ThenErrorCodeShouldBe(string expectedCode)
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
var body = await response.Content.ReadAsStringAsync();
var data = JsonSerializer.Deserialize<JsonElement>(body);
var code = data.TryGetProperty("code", out var codeEl) ? codeEl.GetString()
: data.TryGetProperty("errorCode", out var ecEl) ? ecEl.GetString()
: null;
code.Should().Be(expectedCode);
}
[Then(@"應回傳未授權錯誤")]
public void ThenUnauthorized()
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().Be(401);
}
[Then(@"應回傳禁止操作錯誤")]
public void ThenForbidden()
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().Be(403);
}
[Then(@"應回傳資源不存在錯誤")]
public void ThenNotFound()
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().Be(404);
}
[Then(@"應回傳驗證錯誤")]
public void ThenValidationError()
{
var response = _ctx.Get<HttpResponseMessage>("LastResponse");
((int)response.StatusCode).Should().Match(code => code == 400 || code == 422);
}
// HttpStatusCode → int(最簡單比較)
((int)response.StatusCode).Should().Be(200);
// 使用 FluentAssertions 的 HttpStatusCode 擴充
response.StatusCode.Should().Be(HttpStatusCode.OK);
// 區間檢查
((int)response.StatusCode).Should().BeInRange(200, 299);
// 內建 flag(200-299 為 true)
response.IsSuccessStatusCode.Should().BeTrue();
Steps/CommonThen/,供所有 feature 重用detail(ProblemDetails)、message、error、title.Should(..., "description", args) 提供失敗時的上下文SuccessSteps 和 FailureSteps 兩個類別已建立ExtractErrorMessage helper 涵蓋常見錯誤回應格式Steps/CommonThen/,供所有 feature 共用