日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

dubbo应用程序的单元测试环境搭建(springtest,powermock,mockito)

發布時間:2024/4/14 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 dubbo应用程序的单元测试环境搭建(springtest,powermock,mockito) 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

轉:http://blog.csdn.net/yys79/article/details/66472797

最近,項目中頻繁用到dubbo,而且java工程用引用了幾十個關聯系統的服務(如用戶認證,基礎服務,客戶平臺)。這些服務都是dubbo服務,對我們僅提供了一個接口,服務通過zookeeper注冊,并給我們提供服務。我們的項目都是基于spring的。spring集成dubbo,就可以對這些外部服務進行注入和使用了。

? ? 但是對于單元測試來說卻出現了難題:領域模型的測試不是問題,主要都是自己的代碼,加上一些mock就可以輕松測試;但是如果我想測試應用服務層(使用外部服務最多的地方),很多情況下就需要啟動spring環境,而這樣就需要加載外部系統的服務了。問題是外部的服務給我們的jar包中,只有服務的接口。啟動時如果按照正常開發環境的配置加載spring context,那么明顯是依賴了外部環境,如果沒有啟動zookeeper或者本機不聯網,抑或是關聯系統沒有啟動,spring context加載將會失敗,這是單元測試的忌諱。如果使用專門的單元測試的spring配置文件,去掉外部關聯系統的consumer配置,啟動會直接失敗,更別提測試了。

?還有寫其他問題,如測試靜態方法,私有方法;mock框架與springtest如何集成。spring的aop代理類如何mock一些默認的實現,測試數據庫如何選擇。總之問題超多。好吧,該進入正題了。

? ?1.測試靜態類,私有方法的問題

? ? ? ? 簡單一句話,用powermock。powermock可以做到修改字節碼而改變類的行為,這不多說了,大家自己搜一下,官網上例子通俗易懂。目前我在maven中的關于powermock,mockito的依賴是這樣加入的:

? ?

[html]?view plain?copy
  • <dependency>??
  • ????????????????<groupId>org.powermock</groupId>??
  • ????????????????<artifactId>powermock-api-mockito</artifactId>??
  • ????????????????<version>1.6.6</version>??
  • ????????????</dependency>??
  • ??
  • ????????????<dependency>??
  • ????????????????<groupId>org.mockito</groupId>??
  • ????????????????<artifactId>mockito-all</artifactId>??
  • ????????????????<version>1.10.19</version>??
  • ????????????</dependency>??
  • ????????????<dependency>??
  • ????????????????<groupId>org.powermock</groupId>??
  • ????????????????<artifactId>powermock-module-junit4</artifactId>??
  • ????????????????<version>1.6.6</version>??
  • ????????????????<scope>test</scope>??
  • ????????????</dependency>??
  • ????????????<dependency>??
  • ????????????????<groupId>org.powermock</groupId>??
  • ????????????????<artifactId>powermock-module-junit4-rule-agent</artifactId>??
  • ????????????????<version>1.6.6</version>??
  • ????????????????<scope>test</scope>??
  • ????????????</dependency>??
  • ????????????<dependency>??
  • ????????????????<groupId>org.powermock</groupId>??
  • ????????????????<artifactId>powermock-module-junit4-rule</artifactId>??
  • ????????????????<version>1.6.6</version>??
  • ????????????????<scope>test</scope>??
  • ????????????</dependency>??
  • ????????????<dependency>??
  • ????????????????<groupId>org.jacoco</groupId>??
  • ????????????????<artifactId>org.jacoco.agent</artifactId>??
  • ????????????????<classifier>runtime</classifier>??
  • ????????????????<version>0.7.9</version>??
  • ????????????????<scope>test</scope>??
  • ????????????</dependency>??
  • ?

    最后的話這個jacoco不是mock的依賴,是一個測試覆蓋率的插件。也推薦一下給大家用,哈哈。

    ?

    ? ? 2.powermock與springtest配合使用的問題

    ? ? ? ? 第一個問題解決了,不錯!第二個問題就來了。spring標準的Runner是SpringJUnit4ClassRunner,如果用這個Runner,那么powermock的@PrepairForTest就沒法使用了(也就是靜態mock,私有方法mock的關鍵),因此如果想使用靜態和私有方法mock就必須使用用Powemock的Runner,但是又如何啟動spring context呢?

    ? ? ?經過一些查找,終于解決了這個問題,方法就是用powermock的代理, 在測試類上加上這樣的注解:

    ? ? ?

    [java]?view plain?copy
  • @PowerMockIgnore({"java.lang.management.*","javax.management.*","javax.xml.*","org.xml.sax.*","org.apache.xerces.*","org.w3c.*"})??
  • @RunWith(PowerMockRunner.class)??
  • @PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)??
  • @ContextConfiguration(locations?=?"classpath:META-INF/spring/test-spring.xml")??
  • ?

    ?

    Runner使用PowerMockRuner(就是RunWith注解的值);使用powermock提供的代理來使用SpringJUnit4ClassRunner;@PowerMockIgnore的作用是忽略一些powermock使用的classloader無法處理的類,不使用的話,啟動用例就會報錯。

    ?

    [java]?view plain?copy
  • classpath:META-INF/spring/test-spring.xml?是單元測試專門的spring配置文件,和域代碼使用的配置有些不同。這個文件我放在/test/resources/spring/目錄下。??
  • ?

    ? 到此,一個基于PowerMock,springtest和Mockito的基本配置就都弄完了。

    上一篇說到powermock的配置,我一般在測試類中再加上繼承spring的測試類:extends AbstractTransactionalJUnit4SpringContextTests ,這樣就基本可以了。

    再來說說上一篇中使用的spring配置文件。主要的不同就是test-spring.xml里面不會包含哪些引用外部服務的consumer,也就是剔除外部dubbo服務。

    但是代碼里有很多注入外部服務的地方,這如何處理呢?這是第三個問題:

    ? 3.注入外部的服務:

    ? ? ? 開始我想了個很笨的方法:在test/文件夾下給外部服務的接口都提供一個空的實現類(implements 接口,然后用eclpse生成默認的方法實現)。這樣基本上就可以啟動了。但是實際使用中,由于外部服務接口也在不斷修改中,會出現不同環境的接口類不一至的情況。比如uat環境的jar包多了或一個方法(雖然我們的程序沒有直接使用),如此一來,我自己搞的空實現類就會報編譯錯誤了。

    ? ?后來想到了一個方法,在/test的代碼中增加一個普通的@Conponent注解的類,類里面使用@Bean注解標明所有外部類的生成方法

    ?

    [java]?view plain?copy
  • @Component??
  • public?class?MockedOuterBeanFactory?{??
  • ????@Bean??
  • ????public?OuterService?outerSerive(){??
  • ????????return?Mocktio.mock(OuterService.class);??
  • ????}??
  • }??


  • ?

    ? 然后在測試類中注入這個MockedOuterBeanFactory,這樣測試環境的spring就可以完整的啟動了。外部的服務在啟動后都是Mocktio生成的代理類,所有方法都會返回默認值。

    在實際測試中如何打樁呢?也很簡單。

    ? ? ? ? ? ?如果我測試一個自己寫的服務(如MyService),MyService又注入了OuterService(外部服務),那么利用spring Bean注入的單例這個特性就可以完成。在MyService的測試類中(MyServiceTest.java),同樣也注入OuterService,在執行MyService的方法之前對OuterService進行打樁。那么由于bean是單例的,MyServiceTest中注入的OuterService實例就是MyService注入的實例。這樣就輕松完成了打樁的工作。如果有特殊原因,main中配置的bean不是單例的,那么可以的話,在test-spring.xml中把它配置為單例的就可以。如果確實情況特殊不允許配置為單例方式,看下一篇吧。

    ?啟動后

    ?解決了spring啟動的問題,然后呢?數據庫

    ? 4.測試數據庫的選擇

    ? 有時候,我們需要測試持久化的內容,比如分頁查詢,不能說測試覆蓋了代碼就可以,還需要驗證查詢到的數據是否符合要求。參考了dbunits之類的東西,最后還是覺得之前使用的h2database是最好的選擇。它可以使用內存模式,不需要外部數據庫的依賴。這樣單元測試才能獨立運行。配置很簡單,

    首先加入依賴:

    ?

    [html]?view plain?copy
  • <dependency>??
  • ????????????<groupId>com.h2database</groupId>??
  • ????????????<artifactId>h2</artifactId>??
  • [html]?view plain?copy
  • <span?style="white-space:pre">??????????</span><version>1.4.191</version>??
  • ????????</dependency>??
  • 至于版本,就自己找個最新的吧。

    ?

    然后在數據源的地方使用如下配置(這也是測試環境spring配置不同于main配置的主要位置):

    ?

    [html]?view plain?copy
  • <bean?id="dataSource"?class="org.apache.tomcat.jdbc.pool.DataSource"??
  • ????????destroy-method="close">??
  • ????????<property?name="poolProperties">??
  • ????????????<bean?class="org.apache.tomcat.jdbc.pool.PoolProperties">??
  • ????????????????<property?name="url"?value="jdbc:h2:mem:testdb;DB_CLOSE_ON_EXIT=FALSE;DB_CLOSE_DELAY=1;MODE=MySQL"/>??
  • ????????????????<property?name="driverClassName"?value="org.h2.Driver"?/>??
  • ????????????????<property?name="username"?value=""?/>??
  • ????????????????<property?name="password"?value=""/>??
  • ????????????????<property?name="validationQuery"?value="SELECT?1"/>??
  • ????????????????<property?name="maxActive"?value="8"?/>??
  • ????????????????<property?name="minIdle"?value="1"/>??
  • ????????????????<property?name="maxIdle"?value="4"?/>??
  • ????????????????<property?name="maxWait"?value="10000"/>??
  • ????????????????<property?name="initialSize"?value="1"/>??
  • ????????????</bean>??
  • ????????</property>??
  • ????</bean>??

  • 注意:MODE=MySQL,這是讓h2模擬mysql庫,如果你使用其他類型的庫,一般也會有對應的Mode,主流數據庫都支持。注意mem項,意思是內存數據庫,這樣配置根本不會生成數據庫文件的,特別適合單元測試(依賴外部環境就不是標準單元測試了)。至于數據源類型,按自己的工程的配置就好,只要使用h2的url和driver就行,這里用的是tomcat數據源。

    ?

    這些配置都做好后,就可以運行真正的powermock,mockito,springtest的單元測試了。下一篇說說怎么測試aop的類。

    ?

    上兩篇中,基本環境和測試方式都說了一下。基本的測試否沒問題了。但是還有些問題需要解決。在我實際的開發中,最主要是是要做有Aop切面的Bean內部注入的bean打樁。

    基本情況是:

    ?MyService是個接口,其實現類MyServiceImpl是@Transactional注解的Bean(這樣注入的MyService實例實際上就是代理了)

    MyServiceImpl注了一個Bean:InnerBean,innerBean是自己工程中實現或其他服務都無所謂

    測試中想使用mock替換這個InnerBean。

    ?

    在spring中,aop用代理實現的。PowerMock不能修改其字節碼。而在測試中,我需要替換MyService代理中的InnerBean實例。開始傷透了腦筋啊。。。

    如果不能打樁,那么必須老老實實的準備fixture才能測試,比如準備數據庫中多個表的數據,才能保證InnerBean完成我的預期結果(這種情況還算好的,有些情況都不能打樁)。

    ?

    這個其實真是不難,只不過之前不太熟悉spring的測試框架(以前拋棄了spring,所以也不怎么研究)。

    springtest有2個Utils類,可以幫助我們拿到MyService代理中的具體實現類:

    ?

    [java]?view plain?copy
  • org.springframework.test.util.AopTestUtils;??
  • org.springframework.test.util.ReflectionTestUtils;??
  • ?

    [java]?view plain?copy
  • MyServiceImpl?impl?=?org.springframework.test.util.AopTestUtils.getTargetObject(MyServiceBean實例);??


  • ?

    這樣就可以拿到具體實現類了,再加一句impl.innerBean = mockInnerBean;就可以用自己打樁過的mock替換注入的innerBean實例了。如果多于一個測試方法,別忘了finally時候替換回來啊。

    impl.innerBean 這里,我一般的注入bean都是是用package級別的,這樣便于測試,不必特別的依賴其他技術就可以替換實現。如果是private的,那么用ReflectionTestUtils吧,具體不用說了,簡單易用。

    總結

    以上是生活随笔為你收集整理的dubbo应用程序的单元测试环境搭建(springtest,powermock,mockito)的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。