zoukankan      html  css  js  c++  java
  • 单元测试不可测试那些类(无抽象、静态类、静态方法)

    实际上“单元测试不可测试那些类(无抽象、静态类、静态方法)”是个伪命题,因为事实是:无抽象、静态类、静态方法都是不可单元测试的。那么,如果我们要写出可测试的代码,又要用到这些静态类等,该怎么办,实际上我们需要两个步骤:

    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:

    View Code
    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吧,所以,为了让客户端程序员找到我们的包装类,可以让包装类以及被包装的类使用同一个命名空间。 

    原文地址:https://www.cnblogs.com/luminji/archive/2012/12/31/2840455.html?utm_source=tuicool&utm_medium=referral
  • 相关阅读:
    3.23.谷歌中国搜索关闭的日子
    在Fedora下成功将Vim打造成适用于C/C++的IDE
    有关内存DC和双缓冲位图的问题汇总
    [转]阶乘 n! 末尾 0 的个数
    [转]各种排序算法
    [转]使用CEGUI的Editbox进行中文输入
    [转]ASP.NET中文件上传下载方法集合
    背包问题的c++解法
    [转]经典C/C++算法
    [转]编写自己的MSN机器人
  • 原文地址:https://www.cnblogs.com/jpfss/p/11382211.html
Copyright © 2011-2022 走看看