1. 程式人生 > >Spring Boot 學習筆記(十二)——單元測試

Spring Boot 學習筆記(十二)——單元測試

依賴關係

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    <scope>test</scope>
</dependency>

1、Service層測試

1、測試肯定是測試介面啊,然後選擇要實現的方法; 2、用IDEA新建測試類; 3、單元測試方法:兩個註解: @RunWith(SpringRunner.class) @SpringBootTest 4、記一個assertThat斷言的例子:

@Test
    public void getLearn(){
        LearnResource learnResource=learnService.selectByKey(1001L);
        Assert.assertThat(learnResource.getAuthor(),is("嘟嘟MD獨立部落格"));
    }
}

下文有詳細介紹。

2、Controller層測試

MockMvc MockMvc實現了對Http請求的模擬,能夠直接使用網路的形式,轉換到Controller的呼叫,這樣可以使得測試速度快、不依賴網路環境,而且提供了一套驗證的工具,這樣可以使得請求的驗證統一而且很方便。 這樣就不用啟動工程也能測試Controller層的介面了。 1、初始化MockMvc物件:

@Before
public void setupMockMvc(){
    mvc = MockMvcBuilders.webAppContextSetup(wac).build(); //初始化MockMvc物件
    session = new MockHttpSession();
    User user =new User("root","root");
    session.setAttribute("user",user); //攔截器那邊會判斷使用者是否登入,所以這裡注入一個使用者
}

例子解析:

/**
     * 獲取教程測試用例
     * @throws Exception
     */
    @Test
    public void qryLearn() throws Exception {
        mvc.perform(MockMvcRequestBuilders.get("/learn/resource/1001")
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
                    .accept(MediaType.APPLICATION_JSON_UTF8)
                    .session(session)
            )
           .andExpect(MockMvcResultMatchers.status().isOk())
           .andExpect(MockMvcResultMatchers.jsonPath("$.author").value("嘟嘟MD獨立部落格"))
           .andExpect(MockMvcResultMatchers.jsonPath("$.title").value("Spring Boot乾貨系列"))
           .andDo(MockMvcResultHandlers.print());
    }

其中:

  1. mockMvc.perform執行一個請求
  2. MockMvcRequestBuilders.get(“/user/1”)構造一個請求,Post請求就用.post方法
  3. contentType(MediaType.APPLICATION_JSON_UTF8)代表傳送端傳送的資料格式是application/json;charset=UTF-8
  4. accept(MediaType.APPLICATION_JSON_UTF8)代表客戶端希望接受的資料型別為application/json;charset=UTF-8
  5. session(session)注入一個session,這樣攔截器才可以通過
  6. ResultActions.andExpect新增執行完成後的斷言
  7. ResultActions.andExpect(MockMvcResultMatchers.status().isOk())方法看請求的狀態響應碼是否為200如果不是則拋異常,測試不通過
  8. andExpect(MockMvcResultMatchers.jsonPath(“$.author”).value(“嘟嘟MD獨立部落格”))這裡jsonPath用來獲取author欄位比對是否為嘟嘟MD獨立部落格,不是就測試不通過
  9. ResultActions.andDo新增一個結果處理器,表示要對結果做點什麼事情,比如此處使用MockMvcResultHandlers.print()輸出整個響應結果資訊

3、assertThat使用

1、基本語法:

assertThat( [value], [matcher statement] );

2、Hamcrest匹配符Matcher: 先導包:org.hamcrest.CoreMatchers.* 例子:

字元相關匹配符
/**equalTo匹配符斷言被測的testedValue等於expectedValue,
* equalTo可以斷言數值之間,字串之間和物件之間是否相等,相當於Object的equals方法
*/
assertThat(testedValue, equalTo(expectedValue));
/**equalToIgnoringCase匹配符斷言被測的字串testedString
*在忽略大小寫的情況下等於expectedString
*/
assertThat(testedString, equalToIgnoringCase(expectedString));
/**equalToIgnoringWhiteSpace匹配符斷言被測的字串testedString
*在忽略頭尾的任意個空格的情況下等於expectedString,
*注意:字串中的空格不能被忽略
*/
assertThat(testedString, equalToIgnoringWhiteSpace(expectedString);
/**containsString匹配符斷言被測的字串testedString包含子字串subString**/
assertThat(testedString, containsString(subString) );
/**endsWith匹配符斷言被測的字串testedString以子字串suffix結尾*/
assertThat(testedString, endsWith(suffix));
/**startsWith匹配符斷言被測的字串testedString以子字串prefix開始*/
assertThat(testedString, startsWith(prefix));
一般匹配符
/**nullValue()匹配符斷言被測object的值為null*/
assertThat(object,nullValue());
/**notNullValue()匹配符斷言被測object的值不為null*/
assertThat(object,notNullValue());
/**is匹配符斷言被測的object等於後面給出匹配表示式*/
assertThat(testedString, is(equalTo(expectedValue)));
/**is匹配符簡寫應用之一,is(equalTo(x))的簡寫,斷言testedValue等於expectedValue*/
assertThat(testedValue, is(expectedValue));
/**is匹配符簡寫應用之二,is(instanceOf(SomeClass.class))的簡寫,
*斷言testedObject為Cheddar的例項
*/
assertThat(testedObject, is(Cheddar.class));
/**not匹配符和is匹配符正好相反,斷言被測的object不等於後面給出的object*/
assertThat(testedString, not(expectedString));
/**allOf匹配符斷言符合所有條件,相當於“與”(&&)*/
assertThat(testedNumber, allOf( greaterThan(8), lessThan(16) ) );
/**anyOf匹配符斷言符合條件之一,相當於“或”(||)*/
assertThat(testedNumber, anyOf( greaterThan(16), lessThan(8) ) );
數值相關匹配符
/**closeTo匹配符斷言被測的浮點型數testedDouble在20.0¡À0.5範圍之內*/
assertThat(testedDouble, closeTo( 20.0, 0.5 ));
/**greaterThan匹配符斷言被測的數值testedNumber大於16.0*/
assertThat(testedNumber, greaterThan(16.0));
/** lessThan匹配符斷言被測的數值testedNumber小於16.0*/
assertThat(testedNumber, lessThan (16.0));
/** greaterThanOrEqualTo匹配符斷言被測的數值testedNumber大於等於16.0*/
assertThat(testedNumber, greaterThanOrEqualTo (16.0));
/** lessThanOrEqualTo匹配符斷言被測的testedNumber小於等於16.0*/
assertThat(testedNumber, lessThanOrEqualTo (16.0));
集合相關匹配符
/**hasEntry匹配符斷言被測的Map物件mapObject含有一個鍵值為"key"對應元素值為"value"的Entry項*/
assertThat(mapObject, hasEntry("key", "value" ) );
/**hasItem匹配符表明被測的迭代物件iterableObject含有元素element項則測試通過*/
assertThat(iterableObject, hasItem (element));
/** hasKey匹配符斷言被測的Map物件mapObject含有鍵值“key”*/
assertThat(mapObject, hasKey ("key"));
/** hasValue匹配符斷言被測的Map物件mapObject含有元素值value*/
assertThat(mapObject, hasValue(value));

4、單元測試的回滾

目的:避免產生垃圾資料,可以在測試方法上開啟事務功能,當然也可以在類上註解事務,這樣所有方法都會回滾。 例子:

@Test
@Transactional
public void add(){
    LearnResource bean = new LearnResource();
    bean.setAuthor("測試回滾");
    bean.setTitle("回滾用例");
    bean.setUrl("http://tengj.top");
    learnService.save(bean);
}

下面直接貼上複製了:

如果你想關閉回滾,只要加上@Rollback(false)註解即可。@Rollback表示事務執行完回滾,支援傳入一個引數value,預設true即回滾,false不回滾。 如果你使用的資料庫是Mysql,有時候會發現加了註解@Transactional 也不會回滾,那麼你就要檢視一下你的預設引擎是不是InnoDB,如果不是就要改成InnoDB。 MyISAM與InnoDB是mysql目前比較常用的兩個資料庫儲存引擎,MyISAM與InnoDB的主要的不同點在於效能和事務控制上。這裡簡單的介紹一下兩者間的區別和轉換方法: MyISAM:MyISAM是MySQL5.5之前版本預設的資料庫儲存引擎。MYISAM提供高速儲存和檢索,以及全文搜尋能力,適合資料倉庫等查詢頻繁的應用。但不支援事務、也不支援外來鍵。MyISAM格式的一個重要缺陷就是不能在表損壞後恢復資料。 InnoDB:InnoDB是MySQL5.5版本的預設資料庫儲存引擎,不過InnoDB已被Oracle收購,MySQL自行開發的新儲存引擎Falcon將在MySQL6.0版本引進。InnoDB具有提交、回滾和崩潰恢復能力的事務安全。但是比起MyISAM儲存引擎,InnoDB寫的處理效率差一些並且會佔用更多的磁碟空間以保留資料和索引。儘管如此,但是InnoDB包括了對事務處理和外來鍵的支援,這兩點都是MyISAM引擎所沒有的。 MyISAM適合:(1)做很多count 的計算;(2)插入不頻繁,查詢非常頻繁;(3)沒有事務。 InnoDB適合:(1)可靠性要求比較高,或者要求事務;(2)表更新和查詢都相當的頻繁,並且表鎖定的機會比較大的情況。(4)效能較好的伺服器,比如單獨的資料庫伺服器,像阿里雲的關係型資料庫RDS就推薦使用InnoDB引擎。

5、附一個MySQL修改引擎的操作:

1、檢視當前MySQL的預設儲存引擎:

mysql> show variables like '%storage_engine%';

2、看user表用了什麼引擎(在顯示結果裡引數engine後面的就表示該表當前用的儲存引擎):

mysql> show create table user;

3、將user表修為InnoDB儲存引擎(也可以此命令將InnoDB換為MyISAM):

mysql> ALTER TABLE user ENGINE=INNODB;

4、如果要更改整個資料庫表的儲存引擎,一般要一個表一個表的修改,比較繁瑣,可以採用先把資料庫匯出,得到SQL,把MyISAM全部替換為INNODB,再匯入資料庫的方式。 轉換完畢後重啟mysql

service mysqld restart