<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      深入淺出裸測之道---單元測試的單元化

      三層架構(gòu)之解耦和單元測試

      業(yè)務(wù)域的簡單案例---構(gòu)造器賦值

      傳統(tǒng)nUnit測試示例

      壞味道?---重構(gòu)的提出

      MSpec的引入--- AAA語法

      Rhino Mock --- 我演我

      AutoMock --- 懶的最高境界

      得心應(yīng)手武器庫:

      • nUnit

      • MSpec

      • Rhino Mock

      • AutoMocking

       本文所涉及使用的工具, 見前文: 我的.Net武器庫 ------ 新.Net架構(gòu)必備工具列表

      三層架構(gòu)之解耦和單元測試

      依賴注入DI很大程度的幫助測試單元化。這對層與層之間的依賴關(guān)系,幾乎是真理。

      如對數(shù)據(jù)讀寫的依賴關(guān)系,用IRepository替換之后,所有用到IRepository的類,如Serivce這一層的ExamService,在測試時,只需要傳入一個Mock的IRepository類,就不需要使用真實(shí)的數(shù)據(jù)庫對它測試了.

      我們的另外一層Controller也用到Service這一層,同樣我為Service這一層的實(shí)現(xiàn)也提出一個接口IExamService,在Controller的構(gòu)造器中傳入IExamService的Mock類。因此,很容易的讓測試關(guān)注于Controller本身的行為和功能。甚至可以在ExamService類實(shí)現(xiàn)之前,我們就可以測試和實(shí)現(xiàn)Controller類。這是依賴注入的優(yōu)勢。

      這一整套分層,解耦和測試我們已經(jīng)實(shí)現(xiàn)了,并形成一個規(guī)范的過程和成形的框架。現(xiàn)在已經(jīng)簡單到按部就班,就能輕松完成,甚至后期都可以考慮自動生成這部分代碼。但這部分現(xiàn)在不是本文的重點(diǎn)。

      業(yè)務(wù)域的簡單案例---構(gòu)造器賦值

      當(dāng)我們的注意力轉(zhuǎn)移到業(yè)務(wù)域時,情景有了悄悄的改變。業(yè)務(wù)域中,類與類之間有更多更復(fù)雜的依賴關(guān)系。相比之下,三層之間反而簡單。

      這里,把我正在做的考試(Exam)類做一個簡單的背景介紹。考試,對于身經(jīng)百戰(zhàn)的我們應(yīng)該不陌生了,讓我們好好分析,看看熟悉身影的陌生之面。另外,我這里考試更多是拿社會化考試作分析目標(biāo)。

      一個考試有三個很重要的要素:考試代碼(考試定義);考區(qū)(北京考區(qū),湖南考區(qū));考試日期。這三個要素,唯一標(biāo)識一個考試,也就是說,同一個考區(qū),同一個考試定義在同日期,我就認(rèn)為是同一個考試。很簡單的邏輯,為了體現(xiàn)這個邏輯,我把這三個要素,放在考試類的構(gòu)造器中。為什么?任何一個要素的缺失,考試對象的存在都沒有任何含義,所以一開始構(gòu)造的時候,就要傳入。從另一個角度,考區(qū)+考試定義+日期是考試的業(yè)務(wù)ID,是唯一標(biāo)識,必須貫穿于業(yè)務(wù)對象的始終。

      看代碼:

       
       public class Exam
          {
              public Exam(District district, ExamDef exam_def, Date date)
              {
                  District = district;
                  ExamDef = exam_def;
                  Date = date;
              }
          }

      通過構(gòu)造器,從外部傳入三個對象后,把它們賦給考試的三不屬性,而這三個屬性是只讀, Private是為了給nHibernate和構(gòu)造器使用的。為什么?如前所說他們是業(yè)務(wù)動,在創(chuàng)建之后,再修改沒有任何含義。

      看代碼:

      public class Exam
          {
              public Exam(District district, ExamDef exam_def, Date date)
              {
                  District = district;
                  ExamDef = exam_def;
                  Date = date;
              }
              public virtual ExamDef ExamDef { get; private set; }
              public virtual District District { get; private set; }
              public virtual Date Date { get;private set; }
          }

       

      傳統(tǒng)nUnit測試示例

      好了,背景已經(jīng)足夠了。讓我們來針對這部分功能進(jìn)行測試。喂,等等,我們……現(xiàn)在有功能嗎?有!我測試的描述就是,

      當(dāng)從構(gòu)造器鏈構(gòu)造考試類時,三個屬性應(yīng)該要賦相應(yīng)的值。

      是的,足夠簡單使我們一目了然,也足夠復(fù)雜,我們需要用測試來保障它的功能。 1. 保證它被運(yùn)行---覆蓋測試;2. 保證它是按我的設(shè)計進(jìn)行的---行為測試。

      看代碼:

      [TestFixture]
          public class when_create_an_exam
          {
              [Test]
              public void it_should_assign_parameters_to_properties()
              {
                  //Arrange
                  var stub_exam_def = new ExamDef("98");
                  var stub_district = new District("01");
                  var stub_date = new Date(2011, 1, 1);
      
                  //Action
                  var subject = new Exam(stub_district, stub_exam_def, stub_date);
      
                  //Assert
                  Assert.AreEqual(stub_district,subject.District);
                  Assert.AreEqual(stub_exam_def,subject.ExamDef);
                  Assert.AreEqual(stub_date,subject.Date);
              }
          }

      引入三個中間變量和另外三個類的定義我就不在這羅嗦了。我的命名方式也曾為人病詬,也不在這辯解。只看實(shí)質(zhì)內(nèi)容:分別創(chuàng)建三個類的實(shí)例,用于測試,至于這三個類的具體內(nèi)容,我其實(shí)并不關(guān)心。所以用個詞Stub來表示我的不關(guān)心。DDD的核心理念之一:名符其實(shí)。最后,我的斷言只判斷屬性的值是否與構(gòu)造器傳入值相符。OK,完成!

      壞味道?---重構(gòu)的提出

      過一段時,間。我們再回頭看看這段測試,會有些小小的不舒服。特別,我們還有更多的類有類似的構(gòu)造器賦值功能,還有更多更復(fù)雜的功能等著我們?nèi)y試,我們在做商業(yè)軟件,不是嗎?隨著類似的測試更得越多。這些小小的不舒服會越積越大。

      這面的測試有什么問題?

      1. 測試有三部分:建立測試環(huán)境;調(diào)用被測功能,(測試的本體);斷言。上面的代碼,我甚至都已經(jīng)刻意用注釋分離出了這么三塊,但仍不是語法級別的分離。

      2. 對第三方的類依賴較為嚴(yán)重,這是本文的重點(diǎn)---單元測試單元化。對Exam類來說ExamDef, District都是插足的第三者。

      3. 測試代碼太多,被測的實(shí)際上只有三行,雖然這不是原則性的問題,但是本著更好,更快,更強(qiáng)的精神,這個問題也是值得解決的。

      好了,你提出的問題已經(jīng)太多了,我沒辦法一下子解決。3個還多?是的,我們的口號是“只要一個好”。

      MSpec的引入--- AAA語法

      言歸正傳,讓我們本著選代和重構(gòu)的原則來把這些問題一個一個解決。是的,測試也需要重構(gòu),測試代碼還有bug呢?一點(diǎn)不奇怪。你沒碰到過?噢,因?yàn)槟愀静粚憸y試代碼。

      關(guān)于測試的三段式,我曾經(jīng)看過有人確實(shí)在nUnit的框架下一步一步重構(gòu),形成良好了測試框架。這里我就不這么麻煩了,直接上工具M(jìn)Spec!測試的三段式,有個說法,叫AAA語法,分別是Arrange,Action,Assert。3A級語法,多酷!

      而MSpec用了自己的名詞,分別是Establish, Because, It。看看下面改造之后的測試代碼就清楚什么意思了。

              看代碼:

        public class When_create_an_exam_by
          {
              private Establish context =
                  () =>
                      {
                          stub_exam_def = new ExamDef("98");
                          stub_district = new District("01");
                          stub_date = new Date(2011, 1, 1);
                      };
      
              private Because of =
                  () => subject = new Exam(stub_district, stub_exam_def, stub_date);
      
              private It should_assign_to_properties =
                  () =>
                      {
                          subject.District.ShouldEqual(stub_district);
                          subject.ExamDef.ShouldEqual(stub_exam_def);
                          subject.Date.ShouldEqual(stub_date);
                      };
      
              private static ExamDef stub_exam_def;
              private static District stub_district;
              private static Date stub_date;
              private static Exam subject;
          }

      再看一看測試運(yùn)行的結(jié)果,就明了代碼即文檔的含義了。

      看截圖:

      test_report

      從nUnit升級到MSpec,給人一種耳目一新的感覺。開始也許會有些不習(xí)慣。但是,一旦習(xí)慣之后再也不想回頭了。

      Rhino Mock --- 我演我

      好了,看看第二個問題。一開始,我們依乎不覺得這是個大問題,不就是直接創(chuàng)建一個依賴美嗎,創(chuàng)建就完了唄,一行代碼而已。仍然,需要提醒注意,我們是在做商業(yè)軟件。一旦展開了,一個類不可能只是一、兩個類,特別是間接關(guān)聯(lián)的,會更多,拔出蘿卜帶出泥。就拿這個考試類來說,在我們的實(shí)際項(xiàng)目中,它還有考試科目列表屬性,還通過報考類與考生有間接聯(lián)系。而報考類又與訂單類,事務(wù)類有交互有關(guān)系。考慮所有這些級聯(lián)關(guān)系,難道我為了測試這個構(gòu)造賦值功能把所有的類全部創(chuàng)建出來?

      再進(jìn)一步思考,我們會給出一個自然的解決方案,把考區(qū)類,考試定義類抽象出兩個接口來,構(gòu)造器傳入接口定義,而不是類本身。這其實(shí)是對層與層之間依賴注入的一個模仿。但是,相信我,這個方向是另一個夢魘的入口。業(yè)務(wù)域和多層之間完全是不同的環(huán)境。不想太深入討論,可能獨(dú)立一篇文章都打不住。

       

      幸好,我們有另一個工具Rhino Mock,能幫助我們解決類的模擬的問題。改造之后的測試代碼如下。唯一的影響是,你需要為被模擬的類,加入一個至少是protected的無參數(shù)構(gòu)造器。這其實(shí)不是個大問題,如果你同時在項(xiàng)目中使用nHibernate的話,也會有類似的要求。

      看代碼:

      public class When_create_an_exam
          {
              private Establish context =
                  () =>
                      {
                          stub_exam_def = MockRepository.GenerateMock<ExamDef>();
                          stub_district = MockRepository.GenerateMock<District>();
                          stub_date = MockRepository.GenerateMock<Date>();
                      };
         	//...此處省略的沒有修改的代碼
          }

      可以看到,這一次的重構(gòu),把考試代碼、考區(qū)代碼等,其實(shí)你根本不關(guān)心的信息已經(jīng)省略掉了。

      AutoMocking --- 懶的最高境界

      到這還不夠,最后一個問題是填飽我們肚子的最有一塊燒餅。

      隆重介紹AutoMocking,自動模擬。當(dāng)你的測試類從AutoMock的Specification類繼承時,它會自動為你創(chuàng)建一個被測試對象subject,并且根據(jù)被測試對象構(gòu)建器的參數(shù)定義,全自動的創(chuàng)建模擬對象。而引用這些模擬對象的方式,

      很簡單Dependency<ExamDef>,就是依賴注入的依賴這個詞。已經(jīng)不需要太多的解釋---名如其實(shí)。

      再看代碼:

      public class When_create_an_exam:Specification<Exam>
          {
              private It should_assign_to_properties =
                  () =>
                      {
                          subject.District.ShouldEqual(DependencyOf<District>());
                          subject.ExamDef.ShouldEqual(DependencyOf<ExamDef>());
                          subject.Date.ShouldEqual(DependencyOf<Date>());
                      };
          }

      三行實(shí)現(xiàn)代碼,對應(yīng)三行測試代碼。簡潔的不能再簡潔了。

      posted @ 2012-05-09 11:19  予沁安  閱讀(3082)  評論(7)    收藏  舉報
      主站蜘蛛池模板: 少妇粗大进出白浆嘿嘿视频| 一区二区不卡国产精品| brazzers欧美巨大| 羞羞影院午夜男女爽爽免费视频 | 日韩中文字幕人妻一区| 在线观看国产成人av天堂| 日本中文字幕久久网站| 精品中文字幕人妻一二| 精品人妻蜜臀一区二区三区| 国产精品三级中文字幕| 中国xxx农村性视频| 午夜射精日本三级| 久久亚洲精品无码播放| 日韩亚洲国产中文字幕欧美| 成人伊人青草久久综合网| 亚洲午夜成人精品电影在线观看| 国产黄大片在线观看画质优化| 无码国产精品一区二区av| 成人精品日韩专区在线观看| 高中女无套中出17p| 在线免费成人亚洲av| 亚洲开心婷婷中文字幕| 亚洲国产精品久久久久秋霞| 男人的天堂av社区在线| 亚洲av永久无码天堂影院| 久久精品国产亚洲av电影| 国产精品中文字幕观看| 亚洲日韩中文字幕在线播放| 午夜免费国产体验区免费的| 最近中文字幕国产精品| 亚洲综合色婷婷中文字幕| 久天啪天天久久99久孕妇| 欧美成人精品三级在线观看| 精品国产成人国产在线视| 久久综合色天天久久综合图片| 99精品国产综合久久久久五月天 | 久久综合伊人| 国产一区二区四区不卡| 成人片黄网站色大片免费毛片 | 国产精品18久久久久久麻辣| 欧美高清狂热视频60一70|