亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb

首頁 > 學院 > 開發設計 > 正文

破除依賴

2019-11-14 14:25:12
字體:
來源:轉載
供稿:網友

  前言:單元測試的時候經常出現一個對象依耐另一個你無法控制的對象,所以這個時候你必須去替代成一個你自己可以控制的對象來擺脫依耐。

1:為什么要破除依賴

1.1:運行速度慢

比喻我們要通過用戶Id判斷用戶是否存在,那么我們這個方法就會依賴數據庫。這樣就成了集成測試,如果大量的測試就會出現速度慢。

1.2:需要配置

由于依賴數據庫,就會配置和數據庫相關的文件。

1.3:一次性測試很多內容,無法定位錯誤信息

比喻這個方法錯誤可能是由于傳入的用戶Id為空,也可能傳入的用戶Id不存在,還可能是數據庫連接斷開等,這樣我們就起不到我們單元測試的目的。

2:存根

一個外部依賴項:指的是系統中的一個對象,被測試的代碼與這個對象發生交互,但是你不能控制這個對象。比喻前端工程師和后臺工程師合作,前端工程師要等待后臺返回的數據來處理,那么后臺就是他的一個外部依賴項。因為他無法控制后臺的代碼

定義:一個存根(stub)是對系統中存在的一個依賴項(或協作者)的可控制的替代物(就是你找一個對象來替換你無法控制的對象)。通過使用存根,你在測試代碼時無需直接處理這個依賴項。(說白了就是一個你自己定義來對象來取代你無法控制的對象)

3:重構代碼設計來提高代碼的可測試性

3.1:抽取接口使底層可替換

 其實底層我們就應該使用接口,這樣上層代碼依賴的是接口而不是具體的對象,使項目具有更好的擴展性,當然這里做事為了更好的測試。

從底層方法中抽出一個接口

public interface IUser    {        /// <summary>        /// 檢驗用戶是否存在        /// </summary>        /// <param name="userId">用戶名</param>        /// <returns></returns>        bool IsExist(string userId);    }

底層訪問數據庫的類

public class User:IUser    {        public bool IsExist(string userId)        {            //從數據庫查詢            //如果有返回true        }    }

待測試的工作單元

public bool IsExistUser(string userId)        {                         var user = new User();             return user.IsExist(userId);        }                        

一個可控制的存根

public class FackUser:IUser    {        public bool WillBevalid = false;                public bool IsExist(string userId)        {            return WillBevalid;            }    }

下面開始注入存根了。

4:依賴注入(在被測試的單元中注入一個偽實現)

4.1:構造參數注入

顧名思義就是實例化的時候在構造參數的時候把偽對象注入

此時我們就要修改我們上面的類了如下

被測試類

public class UserBll    {        PRivate readonly IUser _user;        public UserBll(IUser user)        {            this._user = user;        }        public bool IsExistUser(string userId)        {                        return _user.IsExist(userId);                                }       
}

測試代碼

         [Test]        public void IsExistUser_ExistUser_ReturnsTrue()        {            var fackUser = new FackUser {WillBevalid = true};            var user = new UserBll(fackUser);//注入偽對象            bool result = user.IsExistUser("1");            Assert.IsTrue(result);        }

 關于構造函數注入的總結:使用構造函數注入比較簡單直觀可讀性和理解方面也很不錯。但是也有問題就是當你依賴越來越多的時候,加入構造函數的參數越來越多這樣就會變得難以維護。

使用場景:比喻api的設計就是某些使用者本身就是帶有參數的構造函數那么就可以這么做。

4.2:使用屬性(get;set)注入偽對象

被測試類

public class UserBll    {        public IUser User { get; set; }        public UserBll(IUser user)        {            User = new User();//默認的情況執行正常對象        }        public bool IsExistUser(string userId)        {            return User.IsExist(userId);            }       
}

代碼測試

       [Test]        public void IsGetName_NormalGetName_ReturnsTrue() {            var fackUser = new FackUser { WillBevalid = true };            var user = new UserBll { User = fackUser };//屬性注入            bool result = user.IsExistUser("1");            Assert.IsTrue(result);        }

關于屬性注入總結:和構造函數注入相似不過更易讀,更易編寫。

什么時候使用屬性注入:想表明哪個被測試類的某個依賴項是可選的,或者測試可以放心使用默認創建的這個依賴項,就可以屬性注入

4.3:在工廠中偽造一個成員(偽對象)

我們先看工廠類

public class UserFactory    {        private  IUser _user = null;        public  IUser Create()        {            if (_user != null)                return _user;            return new User();        }        [Conditional("DEBUG")]        public  void SetUser(IUser muser)        {            _user = muser;        }    }

被測試類

public class UserBll    {                public bool IsExistUser(string userId)        {                                            var userFactory = new UserFactory();                                          
return userFactory.Create().IsExist(userId); }

測試代碼

        [Test]        public void IsGetName_NormalGetName_ReturnsTrue() {            var fackUser = new FackUser { WillBevalid = true };            var userFactory = new UserFactory();            userFactory.SetUser(fackUser);//設置自己要注入的偽對象            bool result = new UserBll().IsExistUser("1");            Assert.IsTrue(result);        }

關于偽造方法的總結: 這種方法很簡單,對工廠添加一個你要控制的偽依賴項。對被測試代碼沒什么改變一切還是原樣。

這種方式明顯比前兩種好。相當于加入了一個工廠的緩沖區。在這里可以做一些邏輯上的處理。

4.4:抽取和重寫

 使用這種方法的步驟:

在被測試類:

  • 添加一個返回真真實實的虛工廠的方法;
  • 在正常的代碼中使用工廠方法

在測試項目中:

  • 創建一個新類
  • 聲明這個新類繼承被測試類
  • 創建一個你要替換的接口類型的公共字段(不需要屬性)
  • 重寫虛方法
  • 返回公共字段

在測試代碼中:

  • 創建一個存根類的實例。此存根實現所要求的接口
  • 創建新派生類而非測試類的實例

偽造一個工廠方法

public class UserBll    {                public bool IsExistUser(string userId)        {            var user = UserManager();                return user.IsExist(userId);                             }        protected virtual IUser UserManager()        {                    return new User();        }

創建新類并集成被測試類

public class TestUser : UserBll    {        public TestUser(IUser user) {            _muser = user;        }        private readonly IUser _muser;        protected override IUser UserManager() {            return _muser;        }            }

測試代碼:

        [Test]        public void IsGetName_NormalGetName_ReturnsTrue() {            var fackUser = new FackUser { WillBevalid = true };//存根實例            var testUser = new TestUser(fackUser);//注入偽對象(新派生的類)            bool result = testUser.IsExistUser("1");            Assert.IsTrue(result);        }

關于抽取和重寫注入的總結:寫更少的接口,代碼更容易替換。我覺得這種方法最好,就是留了一條路,不光對于測試,如果哪天發現這代碼不好了,直接可以在底層新添加一個替換即可,不會影響原來的代碼

什么時候使用:當你調用外部依賴項時候想模擬自己想要的值的時候就特別受用。

4.5:重構技術變種

先看被測試類

public class UserBll    {                public bool IsExistUser(string userId)        {return UserManager(userId);                 }        protected virtual bool UserManager(string userId)        {            IUser user = new User();            return user.IsExist(userId);        }            }

創建新類并集成被測試類

public class TestUser : UserBll    {            public bool IsSupported;        protected bool IsGetUserName(string userId) {            return IsSupported;        }    }

測試類

public void IsGetName_NormalGetName_ReturnsTrue() {            var testUser = new TestUser { IsSupported = true };            bool result = testUser.IsExistUser("1");            Assert.IsTrue(result);        }

總結:這和上一種方式其實是很像的,只不過這種更徹底。這種方式更加簡單。不在添加很多的構造函數,設置方法或者工廠類。不過確實不符合面向對象中的封裝原則。暴露了用戶不改看到的東西。

各種依賴注入靈活使用。個人覺得后三種都不錯。

 


發表評論 共有條評論
用戶名: 密碼:
驗證碼: 匿名發表
亚洲香蕉成人av网站在线观看_欧美精品成人91久久久久久久_久久久久久久久久久亚洲_热久久视久久精品18亚洲精品_国产精自产拍久久久久久_亚洲色图国产精品_91精品国产网站_中文字幕欧美日韩精品_国产精品久久久久久亚洲调教_国产精品久久一区_性夜试看影院91社区_97在线观看视频国产_68精品久久久久久欧美_欧美精品在线观看_国产精品一区二区久久精品_欧美老女人bb
这里只有精品在线播放| 亚洲人成电影在线播放| 国产精品青草久久久久福利99| 色爱av美腿丝袜综合粉嫩av| 国产一区二区激情| 中文字幕日韩欧美在线视频| 黄色成人av在线| 一区二区三区四区精品| 欧美日韩黄色大片| 欧美日韩中文字幕综合视频| 韩国视频理论视频久久| 亚洲国产精品资源| 亚洲视频在线播放| 91免费视频国产| 奇米成人av国产一区二区三区| 91精品国产色综合久久不卡98口| 亚洲精品中文字幕av| 国产成人高潮免费观看精品| 精品国模在线视频| 久久国产精品久久久久久| 日韩在线视频观看正片免费网站| 在线播放亚洲激情| 日韩美女激情视频| 亚洲日本成人女熟在线观看| 久久视频在线免费观看| 亚洲欧美日韩一区二区在线| 国产视频观看一区| 国内精品久久久久影院 日本资源| 欧美日韩在线视频一区二区| 国产精品色午夜在线观看| 亚洲国产一区二区三区在线观看| 91地址最新发布| 国产va免费精品高清在线| 91av在线免费观看视频| 精品国产一区av| 国产精品美女主播| 欧美激情一级精品国产| 国产精品国产三级国产aⅴ9色| 国产精品入口免费视频一| 国产精品视频精品视频| 一本大道亚洲视频| 亚洲国产欧美久久| 欧美老女人在线视频| 91精品国产自产在线观看永久| 欧美特黄级在线| 日韩av黄色在线观看| 日韩精品免费在线观看| 欧美大秀在线观看| 国产精品欧美一区二区| 九九热精品视频国产| 国产精品老女人视频| 欧美国产亚洲精品久久久8v| 国模吧一区二区| 国产日韩欧美在线| 91久久久久久久| 欧美激情一级欧美精品| 成人黄色在线播放| 欧美性视频网站| 亚洲区在线播放| 一区二区成人av| 久久久精品中文字幕| 欧美午夜精品久久久久久久| 日韩免费在线播放| 国产视频精品xxxx| 中文字幕欧美精品日韩中文字幕| 亚洲第一黄色网| 欧美日韩精品在线视频| 国产精品女主播视频| 久久天天躁狠狠躁老女人| 日本老师69xxx| 国产精品va在线| 欧美日韩免费网站| 亚洲专区在线视频| 亚洲日本欧美日韩高观看| 久久人人看视频| 久久精品一本久久99精品| 日韩av免费一区| 亚洲人成在线播放| 久久久免费高清电视剧观看| 欧美成人免费大片| 色噜噜亚洲精品中文字幕| 影音先锋日韩有码| 色视频www在线播放国产成人| 国产成人免费av| 性色av一区二区三区红粉影视| 久久精品视频在线播放| 日本91av在线播放| 亚洲国产精品嫩草影院久久| 亚洲一区二区免费| 国产精品久久久久久久久免费看| 久久久久久久久久久人体| 岛国av一区二区三区| 久久免费视频在线| 九九视频这里只有精品| 不卡av电影院| 亚洲精品按摩视频| 久久偷看各类女兵18女厕嘘嘘| 亚洲欧洲日韩国产| 成人激情视频在线播放| 亚洲欧美另类国产| 国产美女精品视频免费观看| 亚洲综合中文字幕在线| 亚洲欧洲在线看| 亚洲人成网7777777国产| 久久亚洲综合国产精品99麻豆精品福利| 国产精品久久视频| 成人www视频在线观看| 国内精品视频在线| 亚洲高清免费观看高清完整版| 91牛牛免费视频| 日韩精品中文字幕视频在线| 色哟哟亚洲精品一区二区| 日韩电影视频免费| 88国产精品欧美一区二区三区| 亚洲tv在线观看| 亚洲欧美一区二区激情| 久久99国产精品久久久久久久久| 亚洲综合第一页| 欧美亚洲视频在线观看| 91精品久久久久久久久中文字幕| 97国产suv精品一区二区62| 国产日韩欧美中文在线播放| 亚洲www在线| 国产精品久久久久久亚洲影视| 欧美黑人极品猛少妇色xxxxx| 日本一区二区三区在线播放| 精品国产拍在线观看| 亚洲人成亚洲人成在线观看| 成人深夜直播免费观看| 夜色77av精品影院| 国产成人小视频在线观看| 亚洲综合自拍一区| 亚洲免费高清视频| 亚洲影影院av| 国产日韩在线视频| 黄网站色欧美视频| 亚洲理论电影网| 国产亚洲精品va在线观看| 狠狠综合久久av一区二区小说| 91久久精品在线| 精品动漫一区二区| 国产精品爽黄69天堂a| 久热在线中文字幕色999舞| www.欧美三级电影.com| 国产精品91视频| 欧美激情一区二区三区久久久| 国产美女精品免费电影| 另类视频在线观看| 日韩精品免费一线在线观看| 久久手机免费视频| 欧美日韩国产91| 国产精品扒开腿爽爽爽视频| 国产日韩欧美在线观看| 国产精品高潮呻吟久久av野狼| 日本成熟性欧美| 亚洲人成网站999久久久综合| 欧美电影在线播放| 欧美日韩亚洲视频一区| 一区二区国产精品视频| 久久久999国产精品| 精品久久中文字幕| 欧美精品18videos性欧美| 欧美在线免费观看| 国产亚洲精品久久久久动|