對Service 進行了單元測試,經過mock的方式實現。web
1、對Action層的單元測試實現
一、首先在pom文件中須要引入的依賴spring
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.12</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-core</artifactId> <version>1.10.19</version> <scope>test</scope> </dependency> <dependency> <groupId>org.apache.struts</groupId> <artifactId>struts2-junit-plugin</artifactId> <version>2.1.8</version> <scope>test</scope> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>3.2.8.RELEASE</version> </dependency>
說明:
在此處咱們引入struts2-junit-plugin.2.1.8.jar,由於其裏面有測試Struts2中action的類
StrutsSpringTestCase,用來測試ssh中的action。
二、新建一個測試類
若是你使用的是idea,那麼你能夠直接在須要創建測試類的Action類中
按ctrl+shift+t,新建一個測試類。如DepartmentActionTest
三、若是是普通的action的話,
待測試代碼:apache
public String findById() { String did = ServletActionContext.getRequest().getParameter("did"); department=departmentService.findByDid(Integer.valueOf(did)); return "goEditDepartment"; }
測試代碼:json
@Test public void testFindById() throws Exception { /*這個函數至關@Before註解的函數,是調用單元測試後的時候, 首先會執行的方法。能夠在這裏面作一些必要的準備工做*/ request.setParameter("did", "1"); ActionProxy proxy = getActionProxy("/department_findById.action"); DepartmentAction action = (DepartmentAction) proxy.getAction(); String result = action.findById(); Assert.assertEquals("goEditDepartment", result); }
四、若是是返回json的action的話,待測試代碼:api
public void findAll() { List<Department> departmentList= departmentService.findAll(); JSONObject jsonObject = new JSONObject(); if (CollectionUtils.isEmpty(departmentList)) { jsonObject.put("key", "success"); jsonObject.put("data", JSON.toJSONString(departmentList)); writeJson(jsonObject); return; } jsonObject.put("key", "success"); jsonObject.put("data", JSON.toJSONString(departmentList)); writeJson(jsonObject); }
測試代碼:session
String result = executeAction("/json_findAll.action"); Assert.assertNotNull(result); JSONObject jsonObject = JSON.parseObject(result); if ("success".equals(jsonObject.getString("key"))) { List<Department> departmentList = JSON.parseArray(jsonObject.getString("data"), Department.class); if (CollectionUtils.isEmpty(departmentList)) { return; } for (Department department : departmentList) { System.out.println(department.toString()); } }
五、關於lazy問題的解決:首先在setUp()函數中加入下述代碼:app
@Override protected void setUp() throws Exception { super.setUp(); SessionFactory sessionFactory = lookupSessionFactory(request); Session hibernateSession= getSession(sessionFactory); TransactionSynchronizationManager.bindResource(sessionFactory, new SessionHolder(hibernateSession)); //在只讀模式下(FlushMode.NEVER/MANUAL)寫操做不被容許 hibernateSession.setFlushMode(FlushMode.AUTO); }
而後在添加兩個私有函數框架
private Session getSession(SessionFactory sessionFactory) throws DataAccessResourceFailureException { Session session = sessionFactory.openSession(); FlushMode flushMode = FlushMode.NEVER; if (flushMode != null) { session.setFlushMode(flushMode); } return session; } private SessionFactory lookupSessionFactory(HttpServletRequest request) { //「sessionFactory」是你spring配置文件(一般是application.xml)中的SessionFactory。 //如:org.springframework.orm.hibernate4.annotation.AnnotationSessionFactoryBean return (SessionFactory)this.applicationContext.getBean("sessionFactory"); }
說明:經過lookupSessionFactory()方法獲取這個測試環境中的org.hibernate.SessionFactory實體對象,其中
applicationContext是org.springframework.context.ApplicationContext的實現org.springframework.context.support.GenericApplicationContext
咱們能夠經過它的getBean方法來獲取你配置文件中配置的SessionFactory。使用註解是org.springframework.orm.hibernate4.annotation.AnnotationSessionFactoryBean
不須要使用註解的時候可使用org.springframework.orm.hibernate.LocalSessionFactoryBean來實現。dom
該單元測試須要加載spring配置文件信息,默認加載路徑是你項目的src目錄下,文件名默認爲applicationContext.xml,若是路徑不對或者
文件名不一樣,則須要重寫getContextLocations()方法,如ssh
protected String getContextLocations() { return "classpath*:applicationContext.xml"; }
關於實現web session的問題,很簡單,該類提供了一個MockHttpServletRequest成員變量,咱們只要mock一個session出來,而後加入到這個request中,就能夠實現session的模擬了。示例代碼以下:
HttpSession session = new MockHttpSession(); String sessionId = UUID.randomUUID().toString(); session.setAttribute(ConstParameter.USER_SESSION, sessionId); //user是一個用戶信息的類,你能夠根據你的須要本身定義 UserInfor user = new UserInfo(); user.setUserId(1); user.setName("xxx"); session.setAttribute(ConstParameter.USER_INFO, user); request.setSession(session);
關於action的單元測試咱們就說完了。
2、Service的單元測試
接下來咱們在說說關於service的測試,
一樣,咱們先從依賴提及,須要添加的依賴:
<powermock.version>1.7.1</powermock.version> <!--********************powermock使用*********************--> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-module-junit4</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency> <dependency> <groupId>org.powermock</groupId> <artifactId>powermock-api-mockito</artifactId> <version>${powermock.version}</version> <scope>test</scope> </dependency>
此處咱們採用的是powermock+junit 進行mock測試。爲啥使用powermock呢,毋庸置疑,因爲他的功能比較強大
一、首先,咱們咱們看看待測試的代碼:
@Override public List<MyInvoice> getMyInvoice(String buyerId) { if (StringUtils.isBlank(buyerId)) { return null; } List<MyInvoice> myInvoices = new ArrayList<MyInvoice>(); String url = baseDataUrl + UrlConfig.GET_MYINVOICE_URL + "?t=" + VerifyBaseUtil.getT() + "&token=" + VerifyBaseUtil.getToken() + "&buyerId=" + buyerId; System.out.println("MyInvoiceServiceImpl getMyInvoice接口請求參數爲:" + url); try { String responseInfo = HttpUtil.getHttp(url); System.out.println("MyInvoiceServiceImpl getMyInvoice接口返回結果爲:" + responseInfo); Map<String, Object> result = JSON.parseObject(responseInfo, Map.class); if (DistrictReturnNum.SUCCESS.getValue().equals(result.get("code"))) { myInvoices = JSON.parseArray(JSON.toJSONString(result.get("result")), MyInvoice.class); return myInvoices; } } catch (Exception e) { System.out.println("MyInvoiceServiceImpl getMyInvoice 程序出錯,查詢發票失敗"+e.getMessage()); return null; } return null; }
getMyInvoice方法是一個調用外部接口的方法,經過http協議進行通訊。這兒有兩個問題
1.HttpUtil.getHttp(url) 是一個靜態方法,咱們如何mock?
2.咱們如何mock這個方法所在的實現類?由於該實現類是經過spring ioc 容器生成並注入的。
要回答這兩個問題,咱們首先須要看看,咱們的測試代碼:
```
@RunWith(PowerMockRunner.class)
@PrepareForTest(HttpUtil.class)
public class MyInvoiceServiceImplTest {
@InjectMocks
private MyInvoiceService myInvoiceService = new MyInvoiceServiceImpl();
@Before
public void setUp(){
PowerMockito.mockStatic(HttpUtil.class);
}
@Test
public void testGetMyInvoice() throws Exception {
String result_http="{"result":[{"addDate":1509010776000,"buyerId":" +
""9E59A2D27B7748848FB65041B854240E","headName":"項偉測試"," +
""headType":"0","invoiceId":"9747A51B57FF4EA781F1CFDF73A0D9DF"," +
""invoiceType":"0","isDefault":0},{"addDate":1509092635000,"" +
"buyerId":"9E59A2D27B7748848FB65041B854240E","editDate":1509094177000,"headName":"項偉測試二","headType":"0","invoiceId":"720CF6C50E594283B01C79D03D6D52B2"" +
","invoiceType":"0","isDefault":1}],"msg":"成功","code":104}";
// 一、 buyerId爲空
String buyerId = null;
Assert.assertEquals(null, myInvoiceService.getMyInvoice(buyerId));
// 二、buyerId不爲空
buyerId = "FF8080810F5E601526";
PowerMockito.when(HttpUtil.getHttp(anyString())).thenReturn(result_http);
List
Assert.assertEquals(2,result.size());
}
}
```
第一個問題:咱們經過PowerMockito.mockStatic(HttpUtil.class); 一個靜態方法的實現類。而後就能夠調用該靜態方法。
第二個問題:@InjectMocks註解來mock咱們須要測試的業務類。
至此,咱們就能夠經過powermock對service層的方法進行單元測試了。