<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          小白都能看懂的 Spring Boot 單元測(cè)試

          共 7266字,需瀏覽 15分鐘

           ·

          2021-09-17 10:15


          點(diǎn)擊下方“IT牧場(chǎng)”,選擇“設(shè)為星標(biāo)”

          前言

          何為單元測(cè)試

          單元測(cè)試的目的: 測(cè)試當(dāng)前所寫的代碼是否是正確的, 例如輸入一組數(shù)據(jù), 會(huì)輸出期望的數(shù)據(jù); 輸入錯(cuò)誤數(shù)據(jù), 會(huì)產(chǎn)生錯(cuò)誤異常等. 在單元測(cè)試中, 我們需要保證被測(cè)系統(tǒng)是獨(dú)立的(SUT 沒有任何的 DOC), 即當(dāng)被測(cè)系統(tǒng)通過測(cè)試時(shí), 那么它在任何環(huán)境下都是能夠正常工作的. 編寫單元測(cè)試時(shí), 僅僅需要關(guān)注單個(gè)類就可以了. 而不需要關(guān)注例如數(shù)據(jù)庫(kù)服務(wù), Web 服務(wù)等組件。

          背景

          進(jìn)行過JavaWeb開發(fā)的同學(xué)都了解,在進(jìn)行后臺(tái)開發(fā)時(shí)不僅需要完成系統(tǒng)功能的開發(fā),為了保證系統(tǒng)的健壯性還要同步編寫對(duì)應(yīng)的單元測(cè)試類。基于Spring Boot開發(fā)的項(xiàng)目中的test包用于存放單元測(cè)試類,同時(shí)也提供了對(duì)應(yīng)的注解來進(jìn)行單元測(cè)試的編寫,本文結(jié)合Mock對(duì)Spring Boot中的單元測(cè)試進(jìn)行總結(jié)。

          環(huán)境:JDK1.8+Spring Bootmockito

          單元測(cè)試的引入

          Spring Boot中引入單元測(cè)試只需在pom文件中加入如下依賴,其中提供了JUnit、SpringBoot Test等常見單元測(cè)試庫(kù)。

          <dependency>
              <groupId>org.springframework.boot</groupId>
              <artifactId>spring-boot-starter-test</artifactId>
              <scope>test</scope>
          </dependency>
          <dependency>
              <groupId>org.mockito</groupId>
              <artifactId>mockito-core</artifactId>
              <version>2.0.111-beta</version>
          </dependency>

          單元測(cè)試的創(chuàng)建

          每個(gè)單元測(cè)試類對(duì)應(yīng)項(xiàng)目中的一個(gè)程序類,每個(gè)單元測(cè)試方法對(duì)應(yīng)程序類中的一個(gè)方法,為保證所測(cè)試方法的正確性,至少需要設(shè)計(jì)四個(gè)以上的測(cè)試用例,包含:正確用例、錯(cuò)誤用例和邊界用例。編寫的注釋事項(xiàng)如下:

          • 測(cè)試類的位置位于項(xiàng)目test包下,包的層級(jí)結(jié)構(gòu)與項(xiàng)目相同;
          • 測(cè)試類的命名規(guī)則通常為 xxxTest.java,其中xxx表示待測(cè)試類名;
          • 測(cè)試類中方法命名規(guī)則為testXxx,其中Xxx表示待測(cè)試方法名 ;
          • 測(cè)試方法上加上注解 @Test;

          話不多說,咱們直接開干。

          常用注解

          當(dāng)下是注解盛行時(shí)代,我們先來了解一下相關(guān)的幾個(gè)注解。

          注解說明
          @RunWith更改測(cè)試運(yùn)行器 ,   缺省值org.junit.runner.Runner
          @Before初始化方法,執(zhí)行當(dāng)前測(cè)試類的每個(gè)測(cè)試方法前執(zhí)行
          @Test測(cè)試方法,在這里可以測(cè)試期望異常和超時(shí)時(shí)間
          @Test(timeout = 10000)超時(shí)測(cè)試方法,若測(cè)試方法未在指定時(shí)間內(nèi)結(jié)束則junit自動(dòng)將其標(biāo)記為失敗
          @Transactional聲明式事務(wù)管理,用于需數(shù)據(jù)庫(kù)事務(wù)管理的測(cè)試方法
          @Rollback(true)數(shù)據(jù)庫(kù)回滾,避免測(cè)試數(shù)據(jù)污染數(shù)據(jù)庫(kù)

          相關(guān)理論和技術(shù)點(diǎn),現(xiàn)在已經(jīng)鋪墊完成,下面,我們使用代碼來實(shí)現(xiàn)。

          代碼實(shí)現(xiàn)

          我們分別做三層的測(cè)試:controller、service、dao

          Service層測(cè)試

          @RunWith(SpringRunner.class)
          @SpringBootTest(classes 
          = Application.class)
          public class UserServiceTest 
          {

              @Autowired
              private UserService userService;

              /**
               * 測(cè)試獲取用戶
               */

              @Test(timeOut = 300000)
              @Transactional
              public void testGetUser() {
                  UserEntity userEntity = userService.findByName("zhangSan");
                  Assert.assertNotNull(userEntity);
                  Assert.assertEquals("zhangSan", userEntity.getName());
              }
          }

          是不是很簡(jiǎn)單呢?

          Controller層測(cè)

          controller層,也可以稱之為網(wǎng)絡(luò)請(qǐng)求測(cè)試。對(duì)于網(wǎng)絡(luò)請(qǐng)求進(jìn)行測(cè)試的情形多見于應(yīng)用的Controller層。Spring測(cè)試框架提供MockMvc對(duì)象,可以在不需要客戶端-服務(wù)端請(qǐng)求的情況下進(jìn)行Web測(cè)試.

          測(cè)試開始之前需要建立測(cè)試環(huán)境,setup方法被@Before修飾。通過MockMvcBuilders工具,創(chuàng)建一個(gè)MockMvc對(duì)象。

          @RunWith(SpringRunner.class)
          @SpringBootTest(classes 
          = Application.class)
          class UserControllerTest 
          {

              @Autowired
              private UserController userController ;
              @Autowired
              private WebApplicationContext context;
              private MockMvc mockMvc;

              @Before
              public void setup(){
                  mockMvc = MockMvcBuilders.standaloneSetup(userController).build;
              }

              /**
               * 獲取用戶列表
               */

              @Test(timeOut = 300000)
              public void testGetUserList() throws Exception {
                  String url = "/user/getUserList";
                  MvcResult mvcResult = mockMvc.perform(MockMvcRequestBuilders.get(url))
                          .andExpect(MockMvcResultMatchers.status().isOk()).andReturn();
                  Assert.assertNotNull(mvcResult);
              }
          }

          DAO層測(cè)試

          由于DAO層的方法直接操作數(shù)據(jù)庫(kù),為避免測(cè)試數(shù)據(jù)對(duì)數(shù)據(jù)庫(kù)造成污染,使用注解@Transactional@Rollback在測(cè)試完成后對(duì)測(cè)試數(shù)據(jù)進(jìn)行回滾。

          @RunWith(SpringRunner.class)
          @SpringBootTest
          public class ScoreControllerTestNew 
          {

              @Autowired
              private UserDao userDao;

              /**
               * 測(cè)試插入數(shù)據(jù)
               */

              @Test
              @Rollback(value = true)
              @Transactional
              public void testInsert() {
                  User userZhang = new User();
                  userZhang.setName("zhangSan");
                  userZhang.setAge(23);
                  userZhang.setGender(0);
                  userZhang.setEmail("[email protected]");
                  int n = userDao.insert(userZhang);
                  Assert.assertEquals(1, n);
              }
          }

          到此,關(guān)于三個(gè)層面的測(cè)試就已經(jīng)搞定了,下面我們來看看,如何使用Mockito模擬數(shù)據(jù)庫(kù)操作。

          使用Mockito模擬數(shù)據(jù)庫(kù)操作

          前面在介紹web請(qǐng)求測(cè)試時(shí)使用了Mock技術(shù),該技術(shù)常用于被測(cè)試模塊(方法)依賴于外部系統(tǒng)(web服務(wù)、中間件或是數(shù)據(jù)庫(kù))時(shí)。

          Mock 的中文譯為仿制的,模擬的,虛假的。對(duì)于測(cè)試框架來說,即構(gòu)造出一個(gè)模擬/虛假的對(duì)象,使我們的測(cè)試能順利進(jìn)行下去。

          Mockito 是當(dāng)前最流行的 單元測(cè)試 Mock 框架。采用 Mock 框架,我們可以 虛擬 出一個(gè) 外部依賴,降低測(cè)試 組件 之間的 耦合度,只注重代碼的 流程與結(jié)果,真正地實(shí)現(xiàn)測(cè)試目的。

          來于網(wǎng)絡(luò),侵刪

          由于web服務(wù)或數(shù)據(jù)庫(kù)不可達(dá)時(shí),可以對(duì)其進(jìn)行Mock,在測(cè)試時(shí)不需要真實(shí)的模塊也可完成測(cè)試。

          常用的Mockito方法如下:

          方法簡(jiǎn)介
          Mockito.mock(classToMock)模擬對(duì)象
          Mockito.when(methodCall).thenReturn(value)參數(shù)匹配
          Mockito.doReturn(toBeReturned).when(mock).[method]參數(shù)匹配(直接執(zhí)行不判斷)
          Mockito.when(methodCall).thenAnswer(answer))預(yù)期回調(diào)接口生成期望值
          Mockito.doNothing().when(mock).[method]不做任何返回

          在使用Mockito對(duì)DAO層的單元測(cè)試進(jìn)行模擬后,得到的新的單元測(cè)試類如下 :

          @RunWith(SpringRunner.class)
          public class UserDaoTest 
          {
              @MockBean
              private UserDao userDao;

              private User userZhang = new User();
              userZhang.setName("zhangSan");
              userZhang.setAge(23);

              @Before
              public void setup() {
                  Mockito.when(userDao.findByName("zhangSan")).willReturn(userZhang);
                  Mockito.when(userDao.findByName("liSi")).willReturn(null);
              }

              @Test
              public void testGetUser() {
                  Assert.assertEquals(userZhang, userDao.findByName("zhangSan"));
                  Assert.assertEquals(null, userDao.findByName("liSi"));
              }
          }

          關(guān)于mockito相關(guān),請(qǐng)參考官網(wǎng):https://site.mockito.org/

          后記

          本文重在用代碼案例講解單元測(cè)試,篇幅有限,先分享到這里,如有不當(dāng)之處,敬請(qǐng)諒解指出。

          干貨分享

          最近將個(gè)人學(xué)習(xí)筆記整理成冊(cè),使用PDF分享。關(guān)注我,回復(fù)如下代碼,即可獲得百度盤地址,無套路領(lǐng)取!

          ?001:《Java并發(fā)與高并發(fā)解決方案》學(xué)習(xí)筆記;?002:《深入JVM內(nèi)核——原理、診斷與優(yōu)化》學(xué)習(xí)筆記;?003:《Java面試寶典》?004:《Docker開源書》?005:《Kubernetes開源書》?006:《DDD速成(領(lǐng)域驅(qū)動(dòng)設(shè)計(jì)速成)》?007:全部?008:加技術(shù)群討論

          加個(gè)關(guān)注不迷路

          喜歡就點(diǎn)個(gè)"在看"唄^_^

          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  亚洲色偷 | 青青青草免费在线 | 亚洲在线成人视频 | 天天高清无码 | 欧美人在线播放成 |