上一篇部落格已經完成了spring4.3與junit4.12的整合,如有疑問歡迎一起探讨學習。接下來将展示單元測試及mockmvc使用。
1、Controller層,在這也是我需要測試的層
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
@Controller
@RequestMapping(value="/")
public class DmController {
@Autowired
private DmService dmService; //服務接口
//儲存對象
@RequestMapping(value="newdm.do",method = RequestMethod.POST)
@ResponseBody
public Object newdm(HttpSession session, DmDTO dmDTO) {
User user = getUser(session);
String name = user.getName();
if(name != null) {
String result = dmService.save(dmDTO);
return Message(String); //Message用于向前端傳回資料對象
}
return null;
}
//get請求,用作頁面跳轉
@RequestMapping(value="returnjsp.do",method=RequestMethod.GET)
public String turnjsp(String id) {
if(id.equals("one")) {
return "/hello/one";
}else {
return "/hello/other";
}
}
}
DmService接口
public interface DmService {
String save(DmDTO dmDTO);
}
DmServiceImpl實作類
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
@Service //要記得加上這個注解,否則無法注入容器
public class DmServiceImpl implements DmService{
@Autowired
private DmDAO dmDAO;
@Override
public String save(DmDTO dmDTO) {
if(dmDTO != null) {
String result = dmDAO.save(dmDTO);
return result;
}
return null;
}
}
DmDAO接口
public interface DmDAO {
String save(DmDTO dmDTO);
}
DmDAOImpl實作類
@Repository //切記要加上該注解
public class DmDAOImpl implements DmDAO{
//真實的DAO實作類中應該是與資料庫互動,這裡為了友善就不寫了
@Override
public String save(DmDTO dmDTO) {
@Override
public String save(DmDTO dmDTO) {
if(dmDTO.getName().length()<5) {
return "儲存成功";
}else {
return "儲存失敗";
}
}
}
單元測試案例:
package cn.wolfcode;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.MediaType;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcResultHandlers.print;
import static org.springframework.test.web.servlet.request.MockMvcResultHandlers.status;
import static org.springframework.test.web.servlet.request.MockMvcResultHandlers.view;
//測試類,需要繼承前面整合好的BaseJunit
public class DmControllerTest extends BaseJunit{
@Autowired
DmController dmController; //這裡是直接從容器中拿出DmController這個bean,這個bean裡使用到的依賴,比如DmService都
@Test //已經注入到這個bean裡,是以下面可以直接用這個bean來調用newdm方法進行測試
public void testNewdm() { //注意:測試方法不能有傳回值,也不能是有參函數
DmDTO dmDTO = new DmDTO();
dmDTO.setName("hao"); //設定長度小于5,應該傳回儲存成功
Message result =(Message) dmController.newdm(session,dmDTO); //這裡使用到的session在BaseJunit中已經使用mockmvc構造了
assertEquals("儲存成功",result.getinfo()); //傳回的對象擷取裡面的資訊
}
//使用mockmc來測試,mockmvc主要是模拟頁面對背景的通路,個人用的不是很習慣
@Test
public void testNewdmWithMockmvc() {
DmDTO dmDTO = new DmDTO();
dmDTO.setName("hao");
String requestJson = JSONObject.toJSONString(dmDTO);//mockmvc隻能傳string類型,對于這種對象類型的需要轉成String類型
mockMvc.perform(post("newdm.do") //這裡的mockMvc在BaseJunit已經定義好,請求url及請求方式,如果被測方法是get,這裡對應的換成get即可
.contentType(MediaType.APPLICATION_JSON) //接受的資料類型
.content(requestJson) //請求的資料内容
.andExpect(status().isOk()) //斷言傳回的狀态是正确的
.session(session) //session的方式,括号内的session也是BaseJunit裡構造好的,可以根據自己的要求構造
).andDo(print()) //結果處理器,用于在控台上列印結果 注意這裡是需要靜态引入
.andReturn();
}
@Test
public void testTurnjsp() {
mockMvc.perform(get("returnjsp.do")) //使用get請求
.andExpect(status().isOk())
.andExpect(view().name("/hello/one")) //使用斷言判斷傳回結果
.andDO(print())
.andReturn();
}
}
這裡也把之前的BaseJunit放出來吧
import javax.sql.DataSource;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.mock.jndi.SimpleNamingContextBuilder;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpSession;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.test.context.web.WebAppConfiguration;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.ui.ModelMap;
import org.springframework.web.context.WebApplicationContext;
@RunWith(SpringJUnit4ClassRunner.class) //指定運作的測試類 該類在spring-test裡,有時無法引入隻能手工敲了
@ContextConfiguration(locations= {"classpath*:/applicationContext.xml"})//spring-test裡的類,這個很重要,把配置檔案裡的内容加載到容器中
@WebAppConfiguration
@Transactional(transactionManager="transactionMananger") //這裡的事務即是取applicationContext.xml的事務
@Rollback //預設為true 即事務復原
public class BaseJunit {
@Autowired
protected WebApplicationContext wac;
protected MockMvc mockMvc;
protected MockHttpSession session;
protected MockHttpServletRequest request;
protected ModelMap map;
@BeforeClass //Junit裡的方法,在整個單元測試運作之前先運作,是以可以用于加載xml等檔案操作,這裡加載jndi.xml,
public static void beforeClass() throws Exception{ //這樣就解決了JNDI連接配接方式不啟動tomcat無法連接配接資料庫的問題
ClassPathXmlApplicationContext app = new ClassPathXmlApplicationContext("classpath*:/jndi.xml");//加一個*會整個項目去找這個xml
DataSource ds = (DataSource) app.getBean("dataSource"); //我們jndi.xml裡配置的資料源id="dataSource"
SimpleNamingContextBuilder builder = new SimpleNamingContextBuilder();
builder.bind("java:com/env/jdbc/hello",ds);//資料源與applicationContext.xml裡的jndiName的value綁定
builder.activate();
}
@Before //每個測試用例執行前都會執行一次
public void setup() { //這裡使用MockMvc構造各種session等,這個看個人需要吧
this.mockMvc = MockMvcBuilders.webAppContextSetup(this.wac).build();
this.session = new MockHttpSession();
this.request = new MockHttpServletRequest();
this.map = new ModelMap();
User us = new User(); //使用者實體類
us.setUmname("lixiaolong");
session.setAttribute("user",us);
}
}
總結:
由于我們使用的是存儲過程,存儲過程裡有commit,是以單元測試執行存儲過程後是無法事務復原的,這個問題我們後面會使用強大的Jmockit來完成。時間問題,後面再來補充經常遇到的報錯問題,重點是後面的Jmockit強大的功能使用。
常見問題:1、org.springframework.beans.factory.NoSuchBeanDefinitionException:No bean named ‘dataSource’ is defind…
主要是沒有加載到資料源,可以檢視資料庫配置是否有問題以及加載的jndi.xm路徑是否正确了
2、java.lang.IllegalStateException:Failed to load ApplicationContext…
Caused by:org.springframework.beans.factory.UnsatisfiedDependencyException:Error creating bean with name ‘*’:Unsatisfied dependency expressed field ‘’; …
沒加@Service/@Repository/@Controller這些注解的話就會報建立bean錯誤的異常。
3、java.lang.IllegalStateException:Failed to load ApplicationContext…
Caused by:java.lang.IllegalStateException:WebApplicationObjectSupport instance[ResourceHttpRequestHandler[locations=[class path resource[easyui/]],resolvers=…]]…
在測試類上加上@WebAppConfiguration注解即可,如BaseJunit裡就加了該注解。