软件测试技术之单元测试不可测试那些类(无抽象、静态类、静态方法)
凌雪 2018-11-02 来源 :网络 阅读 1296 评论 0

摘要:本文将带你了解软件测试技术之单元测试不可测试那些类(无抽象、静态类、静态方法),希望对大家学测试技术有所帮助。

本文将带你了解软件测试技术之单元测试不可测试那些类(无抽象、静态类、静态方法),希望对大家学测试技术有所帮助。


实际上“单元测试不可测试那些类(无抽象、静态类、静态方法)”是个伪命题,因为事实是:无抽象、静态类、静态方法都是不可单元测试的。那么,如果我们要写出可测试的代码,又要用到这些静态类等,该怎么办,实际上我们需要两个步骤:
      1:为它们写一个包装类,让这个包装类是抽象的(继承自接口,或者抽象类,或者方法本身是Virtual的);
      2:通知客户端程序员,使用包装类来代替原先的静态类来写业务逻辑;
      实际上,微软也是这么干的,我在上一篇博文《单元测试WebForm的UI逻辑及文件上传》写到,最典型的不可测试类,那就是WebForm架构的网站中,对Response等的模拟。查看Response这个类:
      namespace System.Web
      {
      public sealed class HttpResponse
      {
      ...
      }
      }
      很明显,如果我们在某个WebForm的后台方法中,直接使用它的话:
      protected void Page_Load(object sender, EvengArgs e)
      {
      this.Response.Write("test u");
      }
        该后台代码逻辑就无法进行单元测试了,因为类似MOQ的框架所依赖的是代码本身具有可被重写行,如果某个类本身是静态的,就无法在运行时用模拟类替换掉实际类。
      所以,写一个包装类吧,我们看到微软为Response写了一个包装类,为HttpResponseWrapper:
      namespace System.Web
      {
      [TypeForwardedFrom("System.Web.Abstractions, Version=3.5.0.0,   Culture=Neutral, PublicKeyToken=31bf3856ad364e35")]
      public class HttpResponseWrapper : HttpResponseBase
      {
      public override bool Buffer
      {
      get
      {
      }
      set
      {
      }
      }
      public override bool BufferOutput
      {
      get
      {
      }
      set
      {
      }
      }
      public override HttpCachePolicyBase Cache
      {
      get
      {
      }
      }
      public override string CacheControl
      {
      get
      {
      }
      set
      {
      }
      }
      public override string Charset
      {
      get
      {
      }
      set
      {
      }
      }
      public override CancellationToken ClientDisconnectedToken
      {
      get
      {
      }
      }
      public override Encoding ContentEncoding
      {
      get
      {
      }
      set
      {
      }
      }
      public override string ContentType
      {
      get
      {
      }
      set
      {
      }
      }
      public override HttpCookieCollection Cookies
      {
      get
      {
      }
      }
      public override int Expires
      {
      get
      {
      }
      set
      {
      }
      }
      public override DateTime ExpiresAbsolute
      {
      get
      {
      }
      set
      {
      }
      }
      public override Stream Filter
      {
      get
      {
      }
      set
      {
      }
      }
      public override NameValueCollection Headers
      {
      get
      {
      }
      }
      public override Encoding HeaderEncoding
      {
      get
      {
      }
      set
      {
      }
      }
      public override bool IsClientConnected
      {
      get
      {
      }
      }
      public override bool IsRequestBeingRedirected
      {
      get
      {
      }
      }
      public override TextWriter Output
      {
      get
      {
      }
      set
      {
      }
      }
      public override Stream OutputStream
      {
      get
      {
      }
      }
      public override string RedirectLocation
      {
      get
      {
      }
      set
      {
      }
      }
      public override string Status
      {
      get
      {
      }
      set
      {
      }
      }
      public override int StatusCode
      {
      get
      {
      }
      set
      {
      }
      }
      public override string StatusDescription
      {
      get
      {
      }
      set
      {
      }
      }
      public override int SubStatusCode
      {
      get
      {
      }
      set
      {
      }
      }
      public override bool SupportsAsyncFlush
      {
      get
      {
      }
      }
      public override bool SuppressContent
      {
      get
      {
      }
      set
      {
      }
      }
      public override bool SuppressFormsAuthenticationRedirect
      {
      get
      {
      }
      set
      {
      }
      }
      public override bool TrySkipIisCustomErrors
      {
      get
      {
      }
      set
      {
      }
      }
      public HttpResponseWrapper(HttpResponse httpResponse)
      {
      }
      public override void AddCacheItemDependency(string cacheKey)
      {
      }
      public override void AddCacheItemDependencies(ArrayList cacheKeys)
      {
      }
      public override void AddCacheItemDependencies(string[] cacheKeys)
      {
      }
      public override void AddCacheDependency(params CacheDependency[]   dependencies)
      {
      }
      public override void AddFileDependency(string filename)
      {
      }
      public override void AddFileDependencies(ArrayList filenames)
      {
      }
      public override void AddFileDependencies(string[] filenames)
      {
      }
      public override void AddHeader(string name, string value)
      {
      }
      public override void AppendCookie(HttpCookie cookie)
      {
      }
      public override void AppendHeader(string name, string value)
      {
      }
      public override void AppendToLog(string param)
      {
      }
      public override string ApplyAppPathModifier(string virtualPath)
      {
      }
      public override IAsyncResult BeginFlush(AsyncCallback callback, object state)
      {
      }
      public override void BinaryWrite(byte[] buffer)
      {
      }
      public override void Clear()
      {
      }
      public override void ClearContent()
      {
      }
      public override void ClearHeaders()
      {
      }
      public override void Close()
      {
      }
      public override void DisableKernelCache()
      {
      }
      public override void DisableUserCache()
      {
      }
      public override void End()
      {
      }
      public override void EndFlush(IAsyncResult asyncResult)
      {
      }
      public override void Flush()
      {
      }
      public override void Pics(string value)
      {
      }
      public override void Redirect(string url)
      {
      }
      public override void Redirect(string url, bool endResponse)
      {
      }
      public override void RedirectPermanent(string url)
      {
      }
      public override void RedirectPermanent(string url, bool   endResponse)
      {
      }
      public override void RedirectToRoute(object routeValues)
      {
      }
      public override void RedirectToRoute(string routeName)
      {
      }
      public override void RedirectToRoute(RouteValueDictionary   routeValues)
      {
      }
      public override void RedirectToRoute(string routeName, object   routeValues)
      {
      }
      public override void RedirectToRoute(string routeName,   RouteValueDictionary routeValues)
      {
      }
      public override void RedirectToRoutePermanent(object routeValues)
      {
      }
      public override void RedirectToRoutePermanent(string routeName)
      {
      }
      public override void RedirectToRoutePermanent(RouteValueDictionary   routeValues)
      {
      }
      public override void RedirectToRoutePermanent(string routeName, object   routeValues)
      {
      }
      public override void RedirectToRoutePermanent(string routeName,   RouteValueDictionary routeValues)
      {
      }
      public override void RemoveOutputCacheItem(string path)
      {
      }
      public override void RemoveOutputCacheItem(string path, string   providerName)
      {
      }
      public override void SetCookie(HttpCookie cookie)
      {
      }
      public override void TransmitFile(string filename)
      {
      }
      public override void TransmitFile(string filename, long offset, long   length)
      {
      }
      public override void Write(string s)
      {
      }
      public override void Write(char ch)
      {
      }
      public override void Write(char[] buffer, int index, int count)
      {
      }
      public override void Write(object obj)
      {
      }
      public override void WriteFile(string filename)
      {
      }
      public override void WriteFile(string filename, bool   readIntoMemory)
      {
      }
      public override void WriteFile(string filename, long offset, long   size)
      {
      }
      public override void WriteFile(IntPtr fileHandle, long offset, long   size)
      {
      }
      public override void WriteSubstitution(HttpResponseSubstitutionCallback   callback)
      {
      }
      }
      }
   
      光从代码本身的角度来说,可以说这个类什么事情也没做,但是它为我们提供了一个抽象体系(从抽象类HttpResponseBase继承),这样的话,我们的客户端代码就可以改写为:
      protected HttpResponseBase _response;
      protected void Page_Load(object sender, EvengArgs e)
      {
      _response.Write("test u");
      }
   
      OK,可测试了,因为我们可以在某个地方注入依赖给_response了。
      注意,包装类的撰写,还可以使用接口,或者干脆也仅仅只是一个类,只要让被包装的这个同名的方法是virtual的就可以了。
        另外,不可测试的那些类,可能往往已经作为稳定版本提交给客户了,我们就不能修改源代码然后告诉客户说你替换下我们的DLL吧,所以,为了让客户端程序员找到我们的包装类,可以让包装类以及被包装的类使用同一个命名空间。    

本文由职坐标整理并发布,希望对同学们有所帮助。了解更多详情请关注职坐标软件测试之测试技术频道!

本文由 @凌雪 发布于职坐标。未经许可,禁止转载。
喜欢 | 0 不喜欢 | 0
看完这篇文章有何感觉?已经有0人表态,0%的人喜欢 快给朋友分享吧~
评论(0)
后参与评论

您输入的评论内容中包含违禁敏感词

我知道了

助您圆梦职场 匹配合适岗位
验证码手机号,获得海同独家IT培训资料
选择就业方向:
人工智能物联网
大数据开发/分析
人工智能Python
Java全栈开发
WEB前端+H5

请输入正确的手机号码

请输入正确的验证码

获取验证码

您今天的短信下发次数太多了,明天再试试吧!

提交

我们会在第一时间安排职业规划师联系您!

您也可以联系我们的职业规划师咨询:

小职老师的微信号:z_zhizuobiao
小职老师的微信号:z_zhizuobiao

版权所有 职坐标-一站式AI+学习就业服务平台 沪ICP备13042190号-4
上海海同信息科技有限公司 Copyright ©2015 www.zhizuobiao.com,All Rights Reserved.
 沪公网安备 31011502005948号    

©2015 www.zhizuobiao.com All Rights Reserved