單元測試WebForm的UI邏輯及文件上傳


BS系統中的UI部分的邏輯測試,最首要的就是要模擬請求(Request)和輸出(Response),而WebForm又跟MVC不一樣,后者的Response,Request等HTTP上下文對象均有接口支持,很容易模擬,而查看WebForm的對應對象,如Response,我們首先看到的聲明就是:

public sealed class HttpResponse

無接口,並且是sealed,換句話說,我們要測試一個如下的的Code-Behind函數的邏輯正確性,該怎么測試:

protected void Page_Load(object sender, EvengArgs e)
{
  this.Response.Write("test u");
}

好在FCL中有現成的包裝類HttpResponseWrapper來解決我們的煩惱(不然得自己寫包裝類),我們將上面的代碼改成如下的形式,它就可以變得可測試:

protected HttpResponseBase _response;

protected override void OnPreLoad(EventArgs e)
{
  base.OnPreLoad(e);
  _response = new HttpResponseWrapper(this.Response);
}

protected void Page_Load(object sender, EvengArgs e)
{
  _response.Write("test u");
}

上面的重構,並不影響原有功能的實現,同時卻將代碼修改成可測試的,

1:首先,this.Response被替代成可以被模擬的HttpResponseBase;

2:其次,方法Page_Load內部不再負責生成被依賴的對象的生成;

         即,我們將_response的生成放到方法的外部。這個外部,可以是構造器等,不過由於webform本身的特殊性,在構造器中,this.Response上下文還不可用,所以在這個例子中放到了OnPreLoad中。 

接下來看看測試類的編寫,先說點額外話,Page_Load是protected的,要讓測試類可以訪問到它,需改成public或者干脆讓測試類繼承我們的當前頁面,這里采用的是后者:

[TestClass]
public class _DefaultTest: _Default        ////很明顯,這里測試的是Default.aspx.cs這個類
{
  public Mock<HttpResponseBase> FakeResponse;

  [TestMethod]
  public void LoadOk()
  {
FakeResponse = new Mock<HttpResponse>();

StringWriter sw = new StringWriter();
FakeResponse.SetupGet(x=>x.OutPut).Returns(sw);
this._response = FakeResponse.Object;

FakeResponse.Setup(x=>x.Write(It.IsAny<string>())).CallBack<string((x)=>
{
  sw.Write(x);
  sw.Flush();
}

this.Page_Load(null,null);
Assert.AreEqual(
  “test u”,
  (FakeResponse.Object.Output as StringWriter).ToString();
  }
}

首先,這個測試方法要測試的是Page_Load方法的邏輯正確性,即:執行完畢,客戶端輸出“test u”,它所依賴的是Response.Write這個方法,這個方法是向客戶端瀏覽器輸出文本,顯然我們的單元測試中是不允許網絡傳輸的,所以我們只能將Response.Write這個行為模擬到內存中去,測試代碼中很大一部分就是模擬這個行為。要深刻理會的是:

1:我們要驗證的是Page_Load行為的准確性,而不是驗證Response.Write的准確性;

2:Response.Write是Page_Load行為中的一種依賴,測試方法要對這種依賴進行模擬;

備注:Response.Write內部使用TextWriter,模擬的時候,我們使用了TextWriter的一個子類,StringWriter。 

上面的例子很簡單,進一步看,我們如何來寫針對文件上傳的單元測試。假設上傳的邏輯是這樣的:

Public void UploadFile()
{
  Var file = _request.Files[0];
  If(file.contentLength==0 || file.ContentLength > 5 * 1024 * 1024)
  {
throw new ArgumentException();
  }
  File.SaveAs(file.FileName);
}

則,其中一個測試用例的代碼應該象如下這樣:

[TestMethod]
public void ThrowExceptionIfFilelengthInvalid()
{
  FakeRequest = new Mock<HttpRequestBase>();
  FakeFiles = new Mock<HttpFileCollectionBase>();
  FakeFile = new Mock<HttpPostedFileBase>();

  FakeFile.SetupGet(x=> x.ContentLength).Returns(6 * 1024 * 1024);
  FakeFiles.SetupGet( x=> x[0]).Returns(FakeFile.Object);
  FakeRequest.SetupGet( x=>x.Files).Returns(FakeFiles.Object);

  this._request = FakeRequest.Object;

  try
  {
this.UploadFile();
Assert.Fail();
  }
  catch(ArugmentOutOfRangeException)
  {
  }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM