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

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

破除依賴

2019-11-14 14:34:26
字體:
來源:轉載
供稿:網友

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

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
国产亚洲一区二区在线| 国产69精品久久久| 精品视频偷偷看在线观看| 一区二区成人av| 91精品国产高清久久久久久| 热久久免费国产视频| 国内精品模特av私拍在线观看| 中文字幕欧美亚洲| 国产福利视频一区二区| 91亚洲一区精品| 欧美精品亚州精品| 亚洲黄色www网站| 茄子视频成人在线| 亚洲精品国产精品久久清纯直播| 欧美美女18p| 中文字幕一区二区三区电影| 国产中文字幕亚洲| 91av视频在线免费观看| 亚洲日本成人女熟在线观看| 国产视频999| 亚洲va欧美va国产综合剧情| 欧美老女人xx| 久久99亚洲精品| 国产69精品久久久| 日产日韩在线亚洲欧美| 91精品国产综合久久香蕉最新版| 国产精品久久久久久久久久久久久| 亚洲精品一区久久久久久| 97在线视频观看| 欧美成人亚洲成人| 高跟丝袜欧美一区| 欧美性xxxx在线播放| 欧美裸体xxxx极品少妇软件| 日韩欧美国产成人| 国产成人精品日本亚洲| 黄色一区二区在线| 91精品成人久久| 18性欧美xxxⅹ性满足| 久久全球大尺度高清视频| 久久久久亚洲精品成人网小说| 91av免费观看91av精品在线| 在线精品播放av| 欧美一区二区三区精品电影| 亚洲成人a**站| 国产日韩综合一区二区性色av| 国产精品一二三视频| 美女扒开尿口让男人操亚洲视频网站| 国产精品欧美日韩久久| 91在线直播亚洲| 亚洲精品91美女久久久久久久| 国产精品影片在线观看| 亚洲成人在线网| 社区色欧美激情 | 97在线视频免费观看| 日日噜噜噜夜夜爽亚洲精品| 精品久久久久久国产| 日韩在线免费视频观看| 久久露脸国产精品| 最近2019好看的中文字幕免费| 91国产视频在线播放| 亚洲欧美第一页| 精品成人av一区| 成人亲热视频网站| 日韩精品中文字幕在线| 国产成人欧美在线观看| 欧美中文字幕在线视频| 国产视频久久久久久久| 欧美性高跟鞋xxxxhd| 韩曰欧美视频免费观看| 欧美理论在线观看| 国产亚洲精品久久久久久| 欧美在线视频一区二区| 精品国内亚洲在观看18黄| 尤物yw午夜国产精品视频明星| 欧美午夜精品久久久久久久| 国产精品一区二区三区毛片淫片| 国产一区二区三区在线| 有码中文亚洲精品| 久久久久免费精品国产| 亚洲视频999| 国产美女直播视频一区| 成人激情在线播放| 欧美电影在线观看高清| 亚洲加勒比久久88色综合| 久久伊人精品视频| 欧美成人国产va精品日本一级| 一区二区欧美日韩视频| 亚洲第一区在线| 欧美成人sm免费视频| 国产ts一区二区| 久久精品国产精品亚洲| 国产精品福利在线观看| 欧美午夜电影在线| 欧美精品在线观看91| 美女黄色丝袜一区| 2020久久国产精品| 亚洲电影成人av99爱色| 色999日韩欧美国产| 亚洲人午夜色婷婷| 中文字幕精品av| 欧美第一页在线| 性欧美xxxx交| 国外成人在线播放| 欧美精品18videos性欧| 亚洲成人亚洲激情| 国产高清在线不卡| 成人免费网站在线观看| 国产精品久久久久久久久借妻| 奇门遁甲1982国语版免费观看高清| 午夜精品久久久久久99热软件| 欧美激情视频网址| 国产免费一区二区三区在线能观看| 久久久久久91香蕉国产| 欧美激情乱人伦| 欧美大奶子在线| 亚洲黄色www网站| 国模吧一区二区三区| 91久久久久久久久久久久久| 97在线视频免费观看| 久久久91精品国产| 国产精品欧美激情在线播放| 日韩av片免费在线观看| 国产丝袜高跟一区| 91精品久久久久久久久久| 欧美丰满少妇xxxxx做受| 亚洲成人动漫在线播放| 51色欧美片视频在线观看| 91欧美精品午夜性色福利在线| 粗暴蹂躏中文一区二区三区| 在线午夜精品自拍| 粉嫩老牛aⅴ一区二区三区| 日韩精品亚洲精品| 国产精品亚洲美女av网站| 中文字幕av一区二区| 久久精品一区中文字幕| 97超级碰在线看视频免费在线看| 国产在线精品成人一区二区三区| 日韩中文字幕在线精品| 国产美女扒开尿口久久久| 在线观看欧美成人| 久久综合国产精品台湾中文娱乐网| 亚洲iv一区二区三区| 在线亚洲男人天堂| 国产欧美精品日韩精品| 91麻豆国产语对白在线观看| 国产精品99久久久久久久久| 日韩av网站在线| 国语自产精品视频在线看一大j8| 精品国产一区二区三区久久久| 成人黄色av播放免费| 国产a∨精品一区二区三区不卡| 2019最新中文字幕| 日韩中文字幕视频| 亚洲xxxx妇黄裸体| 国产精国产精品| 91在线免费看网站| 欧美激情久久久久久| 亚洲新声在线观看| 91精品久久久久久久久| 欧美性猛交xxxx免费看漫画| 亚洲精品www久久久久久广东| 国产免费观看久久黄| 国模私拍一区二区三区| 色综合色综合久久综合频道88|