PowerMock+Mockito+MockMvc實現Controller,Service,Mapper全覆蓋測試
目錄
- 使用H2資料庫測試
使用PowerMock和Mockito進行Service層測試
- 簡單方法如何測試
- 複雜方法如何測試
使用MockMvc進行Controller層單元測試
- 簡單方法如何測試
- 需要登陸或者許可權的方法如何測試
- 使用SpringTest進行Dao層測試
1.使用H2資料庫測試
配置檔案:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd" >
<jdbc:embedded-database id="dataSource" type="H2" database-name="cardapy">
<jdbc:script location="classpath:h2_type.sql"/>
<jdbc:script location="classpath:create-db-res.sql"/>
<jdbc:script location="classpath:insert-data.sql"/>
</jdbc:embedded-database >
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:conf/mybatis-config.xml"/>
<property name="typeAliasesPackage" value="com.cardpay,
com.cardpay.common.mapper,
com.cardpay.mgt.usermanager.model"/>
<!--<property name="mapperLocations" value="**/model/*.xml"/>-->
<!--返回Map的攔截器-->
<property name="plugins">
<array>
<bean class="com.cardpay.common.intercepts.SqlTimeInterceptor"/>
<bean class="com.cardpay.common.intercepts.MapInterceptor"/>
<bean class="com.github.pagehelper.PageHelper">
<property name="properties">
<value>
rowBoundsWithCount = true
reasonable = true
</value>
</property>
</bean>
</array>
</property>
</bean>
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
<!-- 這裡如果全部掃描的話, 會有問題-->
<property name="basePackage" value="com.cardpay"/>
<property name="markerInterface" value="com.cardpay.common.base.dao.IBaseDao"/>
</bean>
<!-- (事務管理)transaction manager, use JtaTransactionManager for global tx -->
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
資料庫型別:
SET MODE MySQL;
資料庫指令碼:
需要注意的是SQL指令碼不支援註釋,需要刪除如下後才能執行
-- ----------------------------
-- Table structure for b_repayment_plan
-- ----------------------------
DROP TABLE IF EXISTS b_repayment_plan;
CREATE TABLE b_repayment_plan (
id int(11) NOT NULL AUTO_INCREMENT,
application_id int(11) DEFAULT NULL ,
status tinyint(2) DEFAULT NULL ,
repay_date timestamp NULL DEFAULT NULL ,
loan_term varchar(32) DEFAULT NULL ,
monthly_payment varchar(32) DEFAULT NULL ,
real_repay_date timestamp NULL DEFAULT NULL ,
PRIMARY KEY (id),
KEY repayment_applicatin_fk_idx73 (application_id) USING BTREE
) ENGINE=InnoDB AUTO_INCREMENT=37 DEFAULT CHARSET=utf8;
插入的資料:
配置檔案中已經指明database-name所有插入資料時SQL中不需要指定資料庫
INSERT INTO `t_application_var` VALUES ('8', '1', '689', '1', null);
INSERT INTO `t_application_var` VALUES ('561896', '1945', '580', '100', '2');
2.使用PowerMock和Mockito進行Service層測試
1. 簡單方法
在任何需要用到 PowerMock 的類開始之前,首先我們要做如下宣告:
@RunWith(PowerMockRunner.class)
然後,還需要用註釋的形式將需要測試的靜態方法提供給 PowerMock:
@PrepareForTest( { YourClassWithEgStaticMethod.class })
@mock
為一個interface提供一個虛擬的實現。
@InjectMocks
將本test類中的mock(或@mock)注入到被標註的物件中去,也就是說被標註的物件中需要使用標註了mock(或@mock)的物件。
在測試中,可以使用 When().thenReturn()
語句來指定被引用的方法返回任意需要的值,達到覆蓋測試的效果。
assertEquals
為Junit的斷言方法,驗證返回值是否為預期值
verify
驗證在測試中是否呼叫了指定的方法並且是預期的值
@RunWith(PowerMockRunner.class)
@PrepareForTest({ExpertApplicationServiceImpl.class})
public class ExpertApplicationServiceImplTest {
@Mock
private ExpertApplicationMapper expertApplicationMapper;
@Mock
private ApplicationMapper applicationMapper;
@InjectMocks
private ExpertApplicationServiceImpl expertApplicationService;
@Test
public void update() throws Exception {
ExpertApplication expertApplication = new ExpertApplication();
List<ExpertApplication> expertApplicationList = new ArrayList<>();
when(expertApplicationMapper.update(expertApplication)).thenReturn(1);
int updateResult = expertApplicationService.update(expertApplication);
assertEquals(1,updateResult);
verify(expertApplicationMapper).update(expertApplication);
}
原方法:
@Override
public int update(ExpertApplication obj) {
return expertApplicationDao.update(obj);
}
2. 複雜方法
這裡介紹一下稍微複雜一點的方法如何測試
這個方法主要問題是在原方法中使用添加了new出來的物件並呼叫了add方法
如果不做任何處理的話在verify方法add時會丟擲異常,因為測試中new出的物件和verify驗證的物件並不是同一個物件。解決辦法是使用:
whenNew(ExpertApplication.class).withAnyArguments().thenReturn(expertApplication);
這個方法可以在測試程式碼中new的物件也替換為做自己指定的物件!
測試方法:
@Test
public void division() throws Exception {
Integer applicationId = 1234;
String ids = "1,2,3,4,5";
String finalId = "6";
Application application = new Application();
application.setId(applicationId);
ExpertApplication expertApplication = new ExpertApplication();
when(applicationMapper.get(applicationId)).thenReturn(application);
whenNew(ExpertApplication.class).withAnyArguments().thenReturn(expertApplication);
expertApplicationService.division(applicationId,ids,finalId);
verify(expertApplicationMapper).delete(applicationId);
verify(expertApplicationMapper,times(6)).add(expertApplication);
}
原方法:
@Override
public int division(Integer applicationId, String expertIds, String finalExpertId) {
expertApplicationDao.delete(applicationId);
String[] expertIdArray = expertIds.split(",");
Date date = new Date();
//--------------給普通專家進行分案----------
for (String expertId : expertIdArray) {
ExpertApplication expertApplication = new ExpertApplication();
expertApplication.setExpertId(Integer.parseInt(expertId));
expertApplication.setApplicationId(applicationId);
expertApplication.setExpertEvaluationResult(EXPERT_REVIEWING.getStatusKey());
expertApplication.setIfBoss(EXPERT);
expertApplication.setCreatedAt(date);//建立時間
expertApplication.setModifiedAt(date);//更新修改時間
expertApplicationDao.add(expertApplication);
}
//--------------新增終審專家資料------------------------
ExpertApplication expertApplication = new ExpertApplication();
expertApplication.setExpertId(Integer.parseInt(finalExpertId));
expertApplication.setApplicationId(applicationId);
expertApplication.setExpertEvaluationResult(EXPERT_REVIEWING.getStatusKey());
expertApplication.setIfBoss(FINAL_EXPERT);
expertApplication.setCreatedAt(date);//建立時間
expertApplication.setModifiedAt(date);//更新修改時間
expertApplicationDao.add(expertApplication);
//-------------------更新進件狀態---------------------------------------
Application application = applicationDao.get(applicationId);
application.setStatus(EXPERT_REVIEWING.getStatusKey());// 專家評審中
return applicationDao.update(application);
}
3.使用MockMvc進行Controller層單元測試
首先需要繼承基類
@Rollback
@Transactional
@WebAppConfiguration
@ContextConfiguration(name = "child", locations = {"classpath:pccims-servlet-test.xml"})
public abstract class TestEnv extends BaseTest {
protected MockMvc mockMvc;
protected Subject subject;
protected static User baseUser;
static {
baseUser = User.UserBuilder.get().withId(1).withName("manager").withEmail("[email protected]")
.withPassword("7d9ca79d6ead7127c3a17fd00c1e6090").build();
}
@Autowired
private WebApplicationContext webApplicationContext;
@Before
public void setUp() throws Exception {
SecurityManager securityManger = PowerMockito.mock(SecurityManager.class, Mockito.RETURNS_DEEP_STUBS);
ThreadContext.bind(securityManger);
subject = new Subject.Builder(getSecurityManager()).buildSubject();
setSubject(subject);
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
}
protected void setUser(User user, String role) {
PowerMockito.when(subject.getPrincipal()).thenReturn(user);
if (StringUtils.isNotEmpty(role)) {
PowerMockito.when(subject.hasRole(role)).thenReturn(true);
} else {
role = user.getName();
switch (role) {
case Constant.ROLE_ADMIN:
PowerMockito.when(subject.hasRole(Constant.ROLE_ADMIN)).thenReturn(true);
break;
case Constant.ROLE_MANAGER:
PowerMockito.when(subject.hasRole(Constant.ROLE_MANAGER)).thenReturn(true);
break;
case Constant.ROLE_LEADER:
PowerMockito.when(subject.hasRole(Constant.ROLE_LEADER)).thenReturn(true);
break;
case Constant.ROLE_EXPERT:
PowerMockito.when(subject.hasRole(Constant.ROLE_EXPERT)).thenReturn(true);
break;
default:
PowerMockito.when(subject.hasRole(role)).thenReturn(false);
}
}
}
protected void setUser(User user) {
setUser(user, null);
}
}
1.簡單方法
目前介面都是返回json,所以主要測試的就是返回的json是否正確
如何使用JsonPath請參考:
mockMvc.perform
執行一個請求;
delete("/api/experts/1")
構造一個請求
andExpect
新增執行完成後的斷言
@Test
public void deleteTest() throws Exception {
mockMvc.perform(delete("/api/experts/1"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
}
2.需要登陸或者許可權的方法
baseUser預設是客戶經理角色,如需要其他角色許可權可以自行建立User並set
@Test
public void add() throws Exception {
setUser(baseUser);
mockMvc.perform(post("/api/experts").param("name","A").param("cname","趙鐵柱"))
.andExpect(status().isOk())
.andExpect(jsonPath("$.code").value(200));
}
4.使用SpringTest進行Dao層測試
繼承基類
注意此基類和Controller層基類不同
@RunWith(PowerMockRunner.class)
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class)
@WebAppConfiguration
@PowerMockIgnore("javax.management.*")
@ContextConfiguration(locations={ "classpath:spring-core-config-test.xml","classpath:pccims-servlet-test.xml"})
//配置事務的回滾,對資料庫的增刪改都會回滾,便於測試用例的迴圈利用
@Rollback
@Transactional
public abstract class TestEnv{}
Dao層測試比較簡單隻需要在資料庫插入需要的測試資料並且呼叫mapper方法測試SQL返回的資料是否和預期一樣即可
@Autowired
private ExpertMapper expertMapper;
@Test
public void findByDivisionalRules() throws Exception {
Expert expert = new Expert();
expert.setAreaDivisionalRules("陝西");
expert.setProductType("3");
List<Expert> expertList = expertMapper.findByDivisionalRules(expert);
assertTrue(expertList.size() > 0);
}
相關推薦
PowerMock+Mockito+MockMvc實現Controller,Service,Mapper全覆蓋測試
目錄 使用H2資料庫測試 使用PowerMock和Mockito進行Service層測試 簡單方法如何測試 複雜方法如何測試 使用MockMvc進行Controller層單元測試 簡單方法如何測試 需要登陸或者許可權的方法如何測試 使用Spring
SpringBoot專案,使用MockMvc做controller類的JUNIT單元測試
package hello; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.t
Mybatis(攔截器實現)通用mapper及全ORM實現(四)
到目前為止,我們通過mybatis的攔截器完成了一些基礎mapper的功能,接下來我們來看看如何能夠實現一個物件關係對映的全ORM操作。 實體與表、列的定義已經完成了,那剩下要做的就是: 1、定義如何通過物件方式編寫sql語句 2、把查詢物件轉譯成sql去查詢 3、把查詢結
Mybatis(攔截器實現)通用mapper及全ORM實現(五)-- springboot+mybatis多資料來源設定
本篇實際上和mybatisext專案並沒有太大關係了,但在實際專案中脫離不開多個數據源,尤其是主從分離,同樣網上一些資料大同小異而且大部分並不能真正解決問題,所以單獨提出來說一下 假設我們就是要解決一個主從分離,資料來源定義在了application.properties中
springboot+mybatis+springmvc實現資料庫增加資料,除錯時service實現類中mapper物件為空
問題:service實現類裡面執行到Mapper.save(Entity)時,捕捉到空指標異常 通過除錯,發現Mapper為空 解決途徑: 在瀏覽多個回答後,在論壇裡面看到有人回答說,controller層的方法中new 了*ServiceImpl()導致,如下圖 解決方法:註釋掉該條
spring boot專案 mybatis CodeGenerator程式碼自動生成entityVO,controller,service,serviceimpl,dao,mapper程式碼
新專案需要使用spring boot,用freemarker寫程式碼生成模板,能省下很多時間。 因為專案需要entity,requestVO,responseVO,所以需要獲取資料庫資料生成封裝類。 廢話不多說,上程式碼記錄一下。 注:資料型別不全,我只寫了我能用到的
SpringAOP攔截Controller,Service實現日誌管理(自定義註解的方式)
首先我們為什麼需要做日誌管理,在現實的上線中我們經常會遇到系統出現異常或者問題。這個時候就馬上開啟CRT或者SSH連上伺服器拿日子來分析。受網路的各種限制。於是我們就想為什麼不能直接在管理後臺檢視報錯的資訊呢。於是日誌管理就出現了。 其次
使用Spring的@Autowired 實現DAO, Service, Controller三層的注入
簡述: 結合Spring和Hibernate進行開發 使用@Autowired實現依賴注入, 實現一個學生註冊的功能,做一個技術原型 從DAO(Repository) -> Service -> Controller 目錄結構: 使用Maven做本地包管理,
SpringAOP攔截Controller,Service實現日誌管理(自定義註解的方式)(轉載)
http://langgufu.iteye.com/blog/2235556 首先我們為什麼需要做日誌管理,在現實的上線中我們經常會遇到系統出現異常或者問題。這個時候就馬上開啟CRT或者SSH連上伺服器拿日子來分析。受網路的各種限制。於是我們就想為什麼不能直接在
jquery實現復選框全選,全不選,反選中的問題
了解 span htm cli ems 添加 send 籃球 需要 今天試了一下用jquery選擇復選框,本來以為很簡單的東西卻有bug,於是搜索了一下找到了解決方法。 html代碼如下(這裏沒有用任何樣式,就沒有再放css了): <html> <
在CentOS7上通過RPM安裝實現LAMP+phpMyAdmin過程全記錄
isp -s 管理工具 gpgcheck b2c link 5.5 art http 在CentOS7上通過RPM安裝實現LAMP+phpMyAdmin過程全記錄 時間:2017年9月20日 一、軟件環境: IP:192.168.1.71 Hostname:centos73
spring自動掃描的註解@Component @Controller @Service @Repository
改變 包括 alt init 實例 gda context nts str @Component @Controller @Service @Repository的作用 1、@controller 控制器(註入服務)2、@service 服務(註入dao)3、@reposi
js 實現復選框全選 全部選
tails elements 全選 str byname false public xhtml under http://blog.csdn.net/sunwei3160/article/details/38515187 <!DOCTYPE html PUB
js實現復選框全選和不選
onclick check checkbox rip () nbsp title false style <html> <head> <title></title> </head> <style>
【JS】用checked實現複選框全選和全不選
<html> <head> <meta http-equiv="Content-Type" content="text/html; charset=utf8"> <title>無標題文件</title>
spring基於MockMvc的controller測試
@Component public class TestControllerUtil { private MockMvc mockMvc; @Autowired private WebApplicationContext webApplicationContex
js實現複選框全選/全不選/反選
js實現複選框全選/全不選/反選 <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd"> &
JQuery 實現複選框全選反選功能
HTML部分 <body> <input type="checkbox" name="fu">全選(父)<br> <input type="checkbox" name="zi">子1<br> <input ty
react-native ScrollView 實現上拉滑動全屏,下拉恢復原先大小
ScrollView 系列的都可以完成, 比如 FlatView 和 SectionList 都可以。 1 需求 大概就是一個 scroll 元件向上滑動的時候可以完全展示出來。完全展示之後下滑再恢復縮小時的高度。 1.1需求分析 縮小時不允許滾動
jquery實現複選框全選全不選
<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>使用jQuery完成複選框的全選和全不選</title> <script t