junit中比较常用的三种情形:
1.mock log4j,对log进行测试
2.mock DAO,使得测试脱离真实的DB环境,不需要连数据库
3.mock Http,使得测试脱离外部环境,不需要真的去进行Http请求
测试log4j需要的自定义的mock log类:
1.mock log4j,对log进行测试
2.mock DAO,使得测试脱离真实的DB环境,不需要连数据库
3.mock Http,使得测试脱离外部环境,不需要真的去进行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需要的自定义的mock log类:
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;
}
}