qinshang 2013-12-19
junit中比较常用的三种情形:
1.mocklog4j,对log进行测试
2.mockDAO,使得测试脱离真实的DB环境,不需要连数据库
3.mockHttp,使得测试脱离外部环境,不需要真的去进行Http请求
package com.project.service; import com.project.bean.User; import com.project.dao.UserDAO; import com.project.mock.MockLog; import org.apache.commons.logging.LogFactory; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.StatusLine; import org.apache.http.client.methods.HttpUriRequest; import org.apache.http.impl.client.DefaultHttpClient; import org.easymock.EasyMock; import org.junit.Assert; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.powermock.api.easymock.PowerMock; import org.powermock.core.classloader.annotations.PrepareForTest; import org.powermock.modules.junit4.PowerMockRunner; @RunWith(PowerMockRunner.class) @PrepareForTest({TargetService.class, LogFactory.class, DefaultHttpClient.class}) // 告诉PowerMock哪些类需要被mock public class TargetServiceTest { private MockLog mLog; @Before public void setUp() { // 实例化自己的mock log对象 mLog = new MockLog(); // 通过反射对TargetService中的变量log进行mock Whitebox.setInternalState(TargetService.class, "log", mLog); } /** * mock log4j示例 * @throws Exception */ @Test public void testLog4j() throws Exception { // mock TargetService target = PowerMock.createPartialMock(TargetService.class, "method1"); PowerMock.expectPrivate(target, "method1").andThrow(new IOException()); PowerMock.replay(target); // 验证是否抛出IOException Assert.assertEquals(IOException.class , mLog.getExceptionList().get(0).getClass()); // 验证log的条数是否正确 Assert.assertEquals(1, mLog.getLogList().size()); // 验证log输出的错误信息是否正确 Assert.assertEquals("system error" , mLog.getLogList().get(0)); PowerMock.verify(target); } /** * mock DAO,使得测试脱离真实的DB环境,不需要连数据库 * @throws Exception */ @Test public void testMockDAO() throws Exception { // mock TargetService target = PowerMock.createPartialMock(TargetService.class, "method1", "method2"); // mock userDAO UserDAO userDAO = PowerMock.createMock( UserDAO.class ); // 返回数据的准备 User user = new User(); int userId = 28; user.setNickname( "ニックネーム" ); user.setUserid( userId ); // 既然是mock的dao,那么想得到什么都由自己定,脱离了真实的DB环境 EasyMock.expect( userDAO.getUser( EasyMock.anyInt() ) ).andReturn( user ); PowerMock.replay(userDAO); // 将mock userDao注入到目标类中 target.setUserDAO( userDAO ); PowerMock.replay(target); // Dao已经被mock了,接下来根据自己的需求做一些事情 ... // 验证正确性 Assert.assertEquals(expected, actual); PowerMock.verify(userDAO); PowerMock.verify(target); } /** * mock Http,使得测试脱离外部环境,不需要真的去进行Http请求 * @throws Exception */ @Test public void testMockHttp() throws Exception { // mock HttpClient DefaultHttpClient httpClient = PowerMock.createMock(DefaultHttpClient.class); PowerMock.expectNew(DefaultHttpClient.class).andStubReturn(httpClient); // mock HttpResponse HttpResponse response = PowerMock.createMock(HttpResponse.class); EasyMock.expect(httpClient.execute(EasyMock.anyObject(HttpUriRequest.class))).andStubReturn(response); StatusLine statusLine = PowerMock.createMock(StatusLine.class); EasyMock.expect(response.getStatusLine()).andStubReturn(statusLine); // 设定期望的http status code,也可以是404,500等 EasyMock.expect(statusLine.getStatusCode()).andStubReturn(200); HttpEntity entity = PowerMock.createMock(HttpEntity.class); EasyMock.expect(response.getEntity()).andStubReturn(entity); // 设定期望的http响应结果,这里用一个字符串来作为返回值 InputStream inputStream = new ByteArrayInputStream("code:E01".getBytes()); EasyMock.expect(entity.getContent()).andReturn(inputStream); // 已经得到了期望的Http请求结果,接下来根据自己的需求做一些事情 ... PowerMock.replayAll(); // 验证正确性 Assert.assertEquals(expected, actual); PowerMock.verifyAll(); } }
测试log4j需要的自定义的mocklog类:
package com.project.mock; import java.util.ArrayList; import java.util.List; import org.apache.commons.logging.Log; /** * 这是一个自定义的log类,用于mock真实的log4j对象,它可以模拟log4j的各种动作,并且可以订制各种我们希望的动作 * 这里只模仿两个动作,一个是单纯的接收一条message,一个是接收message同时接收一个exception * 这样一来,真实代码中要用到log4j对象记录log的地方,都被这个mock log给替换了,并且所有记录的信息都被记录到这个对象中,供测试用 * @throws Exception */ public class MockLog implements Log { private List<Object> logList = new ArrayList<Object>(); private List<Throwable> exceptionList = new ArrayList<Throwable>(); @Override public void debug(Object arg0) { logList.add(arg0); } @Override public void debug(Object arg0, Throwable arg1) { logList.add(arg0); exceptionList.add( arg1 ); } @Override public void error(Object arg0) { logList.add(arg0); } @Override public void error(Object arg0, Throwable arg1) { logList.add(arg0); exceptionList.add( arg1 ); } @Override public void fatal(Object arg0) { } @Override public void fatal(Object arg0, Throwable arg1) { logList.add(arg0); exceptionList.add( arg1 ); } @Override public void info(Object arg0) { logList.add(arg0); } @Override public void info(Object arg0, Throwable arg1) { logList.add(arg0); exceptionList.add( arg1 ); } @Override public boolean isDebugEnabled() { return false; } @Override public boolean isErrorEnabled() { return false; } @Override public boolean isFatalEnabled() { return false; } @Override public boolean isInfoEnabled() { return false; } @Override public boolean isTraceEnabled() { return false; } @Override public boolean isWarnEnabled() { return false; } @Override public void trace(Object arg0) { logList.add(arg0); } @Override public void trace(Object arg0, Throwable arg1) { logList.add(arg0); exceptionList.add( arg1 ); } @Override public void warn(Object arg0) { logList.add(arg0); } @Override public void warn(Object arg0, Throwable arg1) { logList.add(arg0); exceptionList.add( arg1 ); } public List<Object> getLogList() { return logList; } public void setLogList(List<Object> logList) { this.logList = logList; } public void setExceptionList( List<Throwable> exceptionList ) { this.exceptionList = exceptionList; } public List<Throwable> getExceptionList() { return exceptionList; } }