最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

基于Springboot+Junit+Mockito做單元測試的示例

 更新時間:2018年02月10日 14:28:19   作者:鼯鼠的技術博客  
本篇文章主要介紹了基于Springboot+Junit+Mockito做單元測試的示例,小編覺得挺不錯的,現在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧

前言

這篇文章介紹如何使用Springboot+Junit+Mockito做單元測試,案例選取撮合交易的一個類來做單元測試。

單元測試前先理解需求

要寫出好的單測,必須先理解了需求,只有知道做什么才能知道怎么測。但本文主要講mockito的用法,無需關注具體需求。所以本節(jié)略去具體的需求描述。

隔離外部依賴

Case1. 被測類中被@Autowired 或 @Resource 注解標注的依賴對象,如何控制其返回值

以被測方法 MatchingServiceImpl.java的matching(MatchingOrder buyOrder, MatchingOrder sellOrder)為例

被測類MatchingServiceImpl

public class MatchingServiceImpl implements MatchingService {
  private static final Logger log = LoggerFactory.getLogger(MatchingServiceImpl.class);
  @Autowired
  private QuoteService quoteService;
  ...
  public MatchingResult matching(MatchingOrder buyOrder, MatchingOrder sellOrder) {
    int currentPrice = quoteService.getCurrentPriceByProduct(buyOrder.getProductCode());
    MatchingResult result = new MatchingResult();
    if (sellOrder != null && buyOrder != null &&
        sellOrder.getPrice() <= buyOrder.getPrice()) {
    ...
  }
}

matching方法中的quoteService.getCurrentPriceByProduct(buyOrder.getProductCode());要訪問Redis獲取當前報價,這里我們需要把外部依賴quoteService mock掉,控制getCurrentPriceByProduct方法的返回值。使用mockito可以做到,具體如下:

測試類MatchingServiceImplTest

public class MatchingServiceImplTest extends MockitoBasedTest {
  /**
   * 被@Mock標注的對象會自動注入到被@InjectMocks標注的對象中
   */
  @Mock
  private QuoteService quoteService;
  /**
   * <pre>
   * 被測對象,用@InjectMocks標注,那些被@mock標注的對象就會自動注入其中。
   * 另一個注意點是這里的MatchingServiceImpl是直接new出來(Mockito 1.9版本后不new也可以),而不是通過spring容器注入的。因為這里我不需要從spring容器中
   * 獲得其他依賴,不需要database ,redis ,zookeeper,mq,啥都不依賴,所以直接new
   * </pre>
   */
  @InjectMocks
  private MatchingServiceImpl matchingService = new MatchingServiceImpl();
  @Test
  public void testMatching_SuccessWhenCurrentPriceBetweenBuyPriceAndSellPrice() {
    MatchingOrder buyOrder = new MatchingOrder();
    buyOrder.setPrice(1000);
    buyOrder.setCount(23);
    MatchingOrder sellOrder = new MatchingOrder();
    sellOrder.setPrice(800);
    sellOrder.setCount(20);
    // 方法打樁(Method stubbing)
    // when(x).thenReturn(y) :當指定方法被調用時返回指定值
    Mockito.when(quoteService.getCurrentPriceByProduct(Mockito.anyString())).thenReturn(900);
    MatchingResult result = matchingService.matching(buyOrder, sellOrder);
    org.junit.Assert.assertEquals(true, result.isSuccess());// 斷言撮合是否成功
    org.junit.Assert.assertEquals(20, result.getTradeCount());// 斷言成交數量
    org.junit.Assert.assertEquals(900, result.getTradePrice()); // 斷言最新報價是否符合預期
  }

Case2. 被測函數A調用被測類其他函數B,怎么控制函數B的返回值?

比如,MatchingServiceImpl中有個函數startBuyProcess,它里面調用了該類中的其他函數,如getTopSellOrder,matching,如何控制這兩個函數的返回值?
這里要解決的問題其實是怎么對一個類”部分mock”–被測類的被測方法(如startBuyProcess)要真實執(zhí)行,而另一些方法(如getTopSellOrder)則是要打樁(不真正進去執(zhí)行)。

被測類MatchingServiceImpl

protected void startBuyProcess(MatchingOrder buyOrder, boolean waitForMatching) {
    while (true) {
      //對手方最優(yōu)價
      MatchingOrder topSellOrder = getTopSellOrder(buyOrder.getProductCode());
      MatchingResult matchingResult = matching(buyOrder,topSellOrder);
      if(matchingResult.isSuccess()) {
        doMatchingSuccess(buyOrder,topSellOrder,matchingResult,MatchingType.BUY);
        if(buyOrder.getCount() <= 0) {
          break;
        }
      }else {
        if(waitForMatching) {
          //加入待撮合隊列
          addToMatchingBuy(buyOrder);
        }else {
          //撤單
          sendCancleMsg(buyOrder);
        }
        break;
      }
    }
  }

利用Mockito.spy()可以做到“部分Mock”

測試類MatchingServiceImplTest.testStartBuyProcess_InCaseOfMatchingSuccess

/**
   *
   * 測試StartBuyProcess方法在撮合成功后的處理是否符合預期,即測試startBuyProcess方法進入下面這個判斷分支后的行為
   * {@link MatchingServiceImpl#startBuyProcess(MatchingOrder, boolean)}
   *
   * <pre>
   * if (matchingResult.isSuccess()) {
   *
   *   doMatchingSuccess(buyOrder, topSellOrder, matchingResult, MatchingType.BUY);
   *
   *   if (buyOrder.getCount() &lt;= 0) {
   *     break;
   *   }
   * }
   * </pre>
   *
   */
  @Test
  public void testStartBuyProcess_InCaseOfMatchingSuccess() {
    MatchingOrder buyOrder = new MatchingOrder();
    buyOrder.setPrice(700);
    buyOrder.setCount(23);
    // 用Mockito.spy()對matchingService進行部分打樁
    matchingService = Mockito.spy(matchingService);
    MatchingResult firstMatchingResult = new MatchingResult();
    firstMatchingResult.setSuccess(true);
    firstMatchingResult.setTradeCount(20);
    MatchingResult secondMatchingResult = new MatchingResult();
    secondMatchingResult.setSuccess(false);
    // doReturn(x).when(obj).method() 對方法打樁,打樁后,程序執(zhí)行這些方法時將按照預期返回指定值,未被打樁的方法將真實執(zhí)行
    // 兩個doReturn表示第一次調用matchingService.matching時返回firstMatchingResult,第二次調用返回secondMatchingResult
    // 因為startBuyProcess里有個while循壞,可能會多次執(zhí)行matching方法
    Mockito.doReturn(firstMatchingResult).doReturn(secondMatchingResult).when(matchingService)
        .matching(Mockito.any(MatchingOrder.class), Mockito.any(MatchingOrder.class));
    MatchingOrder sellOrder = new MatchingOrder();
    sellOrder.setPrice(600);
    sellOrder.setCount(20);
    // 對getTopSellOrder方法打樁
    Mockito.doReturn(sellOrder).when(matchingService).getTopSellOrder(Mockito.anyString());
    // 對外部依賴jedis的方法進行打樁
    Mockito.when(jedisClient.incrBy(Mockito.anyString(), Mockito.anyLong())).thenReturn(0L);
    // startBuyProcess是被測函數,不打樁,會真實執(zhí)行
    matchingService.startBuyProcess(buyOrder, true);
    // 后面的校驗和斷言是測試doMatchingSuccess方法的行為的,這也是這個測試的目的
    // verify可用來校驗,某個類的方法被執(zhí)行過多少次,這里是校驗jedisClient.zremFirst是否被執(zhí)行過1次
    Mockito.verify(jedisClient, Mockito.times(1)).zremFirst(Mockito.anyString());
    org.junit.Assert.assertEquals(3, buyOrder.getCount());
    org.junit.Assert.assertEquals(0, sellOrder.getCount());
  }

spy的用法已經演示完畢,下面從testStartBuyProcess_InCaseOfMatchingSuccess說下單元測試的“粒度”。

testStartBuyProcess_InCaseOfMatchingSuccess的目的是想測doMatchingSuccess,我們費了很大勁才把前面的一堆準備工作做完,才能去測doMatchingSuccess。

更好的實踐應該是另起測試方法去單獨測doMatchingSuccess,關注點也集中很多,doMatchingSuccess覆蓋完了,再測startBuyProcess其實就只是覆蓋下它本身的判斷分支就行了。覆蓋率照樣達到,而且測試代碼也更容易維護,testStartBuyProcess_InCaseOfMatchingSuccess由于考慮的職責太多,它很容易受到變化的影響,細小的東西改變,可能就會影響它的正常工作。

引入測試框架Maven依賴

<dependency>
  <groupId>junit</groupId>
  <artifactId>junit</artifactId>
  <version>4.11</version>
  <scope>test</scope>
</dependency>

<dependency>
  <groupId>org.mockito</groupId>
  <artifactId>mockito-all</artifactId>
  <version>1.10.19</version>
  <scope>test</scope>
</dependency>
<dependency>
  <groupId>org.springframework</groupId>
  <artifactId>spring-test</artifactId>
  <version>4.2.5.RELEASE</version>
  <scope>test</scope>
</dependency>

springboot+junit+mockito的上下文構建

MockitoBasedTest

@RunWith(SpringJUnit4ClassRunner.class)
@SpringApplicationConfiguration(classes = TestApplication.class)
public abstract class MockitoBasedTest {
  @Before
  public void setUp() throws Exception {
    // 初始化測試用例類中由Mockito的注解標注的所有模擬對象
    MockitoAnnotations.initMocks(this);
  }
}
// 其他測試類繼承MockitoBasedTest

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持腳本之家。

相關文章

  • 通過JDK源碼分析關閉鉤子詳解

    通過JDK源碼分析關閉鉤子詳解

    一個簡單的關閉鉤子,程序被中斷或者正常退出時會顯示 hook shutdown!非常的優(yōu)雅,有效,巧妙。那么這篇文章就來給大家介紹關于通過JDK源碼分析關閉鉤子的相關資料,文中通過示例代碼介紹的非常詳細,需要的朋友可以參考借鑒。
    2017-11-11
  • 關于@PropertySource配置的用法解析

    關于@PropertySource配置的用法解析

    這篇文章主要介紹了關于@PropertySource配置的用法解析,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2022-03-03
  • Java微信公眾號推送模版消息的步驟示例詳解

    Java微信公眾號推送模版消息的步驟示例詳解

    模板消息是一種向用戶發(fā)送通知的服務,廣泛用于訂單狀態(tài)更新、服務提醒等場景,下面,我將詳細介紹如何使用Java結合微信官方提供的API來實現模板消息的推送,感興趣的朋友跟隨小編一起看看吧
    2024-08-08
  • Java遍歷文件夾下所有文件并重新命名

    Java遍歷文件夾下所有文件并重新命名

    這篇文章主要為大家詳細介紹了Java遍歷文件夾下所有文件并重新命名,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2020-03-03
  • Maven pom中optional配置項詳解及依賴調解原則

    Maven pom中optional配置項詳解及依賴調解原則

    Maven pom中optional配置項詳解及依賴調解原則,情況行為(默認)依賴會傳遞給下游項目依賴僅當前項目可用,不會傳遞當前項目和依賴項目都依賴同一包Maven按“路徑最近”原則選擇版本可選依賴+下游未顯
    2025-10-10
  • Eclipse安裝配置方法圖文教程

    Eclipse安裝配置方法圖文教程

    這篇文章主要為大家詳細介紹了Eclipse安裝配置方法圖文教程,感興趣的小伙伴們可以參考一下
    2016-06-06
  • Spring Boot2+JPA之悲觀鎖和樂觀鎖實戰(zhàn)教程

    Spring Boot2+JPA之悲觀鎖和樂觀鎖實戰(zhàn)教程

    這篇文章主要介紹了Spring Boot2+JPA之悲觀鎖和樂觀鎖實戰(zhàn)教程,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教
    2021-10-10
  • 詳解SpringIOC容器中bean的作用范圍和生命周期

    詳解SpringIOC容器中bean的作用范圍和生命周期

    這篇文章主要介紹了SpringIOC容器中bean的作用范圍和生命周期,本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-02-02
  • SimpleDateFormat格式化日期問題

    SimpleDateFormat格式化日期問題

    這篇文章主要介紹了SimpleDateFormat格式化日期問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-06-06
  • java模擬多線程http請求代碼分享

    java模擬多線程http請求代碼分享

    本篇文章給大家分享了java模擬多線程http請求的相關實例代碼,對此有需要的可以跟著測試下。
    2018-05-05

最新評論

吴川市| 定远县| 平阴县| 株洲市| 修文县| 留坝县| 和田市| 留坝县| 抚州市| 灵丘县| 岑巩县| 孟州市| 晋州市| 长宁县| 陈巴尔虎旗| 湘潭县| 赤峰市| 项城市| 垫江县| 凯里市| 长岛县| 怀化市| 府谷县| 开鲁县| 南和县| 长岭县| 通州区| 安福县| 镇平县| 罗田县| 泗水县| 醴陵市| 茌平县| 横峰县| 扎兰屯市| 即墨市| 泗洪县| 开封市| 郎溪县| 苍山县| 珲春市|