在 ASP.NET MVC 與 ASP.NET Web API 中,會使用有彈性且關注點分離的 ActionFilter
來進行進出 Action 的控制。
然而 ActionFilter
大部分都是在處理 HttpRequest 與 HttpResponse 的內容,該怎麼為 ActionFilter
撰寫獨立的單元測試呢?這篇文章將以一個簡單的自訂 ExceptionFilter
來當範例,說明怎麼模擬 HttpRequest
與 HttpResponse
,尤其是使用了 HttpRequestMessage
的 CreateResponse()
系列方法。
ExceptionFilter 產品代碼說明
當這個 ActionFilter
所覆蓋的範圍內發生 exception 時,為避免吐回給呼叫端的 status code 是 500 Internal Error
,而是希望改成 HttpStatus 是 200 OK
搭配自訂狀態碼。ActionFilter
代碼如下所示。
Controller 在使用時,只需要在 Action 或 Controller 上標記 Attribute 即可,如下圖所示。
單元測試代碼說明
可以看到,要測試 ApiExceptionFilterAttribute
的 OnException()
,最麻煩的地方其實是在初始化 HttpActionExecutedContext
,這個 context 包含了 HttpRequest
與 HttpResponse
的資訊,因為是 ExceptionFilter
的事件,所以還包含了 Exception
的 property。
產生HttpActionExecutedContext
的代碼如下所示:
private HttpActionExecutedContext CreateExecutedContext(Exception exception)
{
return new HttpActionExecutedContext
{
ActionContext = new HttpActionContext
{
ControllerContext = new HttpControllerContext
{
Request = GetHttpRequestMessage()
}
},
Exception = exception,
Response = new HttpResponseMessage()
};
}
private HttpRequestMessage GetHttpRequestMessage()
{
var request = new HttpRequestMessage();
request.Properties[HttpConfigurationKey] = new HttpConfiguration();
return request;
}
HttpConfigurationKey
是 import static: using static System.Web.Http.Hosting.HttpPropertyKeys;
由於在 Web API 的 ActionFilter
中,我們很常會使用 HttpRequestMessage.CreateResponse()
來產生同樣 content-type
的 response,而不是自己 new HttpResponseMessage()
來定義回傳內容,因此需要使用到 HttpConfiguration
。
測試案例如下所示。
整個開發跟重構過程,請見影片。
結論
那一行 request.Properties[HttpConfigurationKey] = new HttpConfiguration();
是關鍵,漏了,就會一直噴奇怪的 NullReferenceException
跟 HttpConfiguration
有問題的錯誤資訊。
blog 與課程更新內容,請前往新站位置:http://tdd.best/