1. PowerMock是什么?
PowerMock是一个Java模拟框架,用于解决测试问题。
举个例子,你在使用Junit进行单元测试时,并不想让测试数据进入数据库,怎么办?这个时候就可以使用PowerMock,拦截数据库操作,并模拟返回参数。
2. PowerMock包引入
<!-- PowerMock JUnit 4.4+ Module -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<!-- PowerMock Mockito2 API -->
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-mockito2</artifactId>
<version>2.0.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
3. 重要注解说明
@RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试
@PrepareForTest({RandomUtil.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PowerMockIgnore("javax.management.*") //为了解决使用powermock后,提示classloader错误
4. 示例
4.1 普通Mock
/***********************Prepare****************************/
public interface MockMapper {
public int count(MockModel model);
}
@Service
public class MockServiceImpl {
@Autowired
private MockMapper mockMapper;
public int count(MockModel model) {
return mockMapper.count(model);
}
}
/*****************************************************/
@RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试
@PrepareForTest({MockUtil.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PowerMockIgnore("javax.management.*") //为了解决使用powermock后,提示classloader错误
public class MockExample {
// 将@Mock注解的示例注入进来
@InjectMocks
private MockServiceImpl mockService;
@Mock
private MockMapper mockMapper;
/**
* mock普通方法
*/
@Test
public void testSelectAppAdvertisementList() {
MockModel model = new MockModel();
PowerMockito.when(mockMapper.count(model)).thenReturn(2);
Assert.assertEquals(2, mockService.count(model));
}
}
2. Mock静态方法
/************************Prepare****************************/
public class MockUtil {
private static final Random random = new Random();
public static int nextInt(int bound) {
return random.nextInt(bound);
}
}
/***************************************************/
@RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试
@PrepareForTest({MockUtil.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PowerMockIgnore("javax.management.*") //为了解决使用powermock后,提示classloader错误
public class MockExample {
@Test
public void testStaticMethod() {
PowerMockito.mockStatic(MockUtil.class);
PowerMockito.when(MockUtil.nextInt(10)).thenReturn(7);
Assert.assertEquals(7, MockUtil.nextInt(10));
}
}
3. Mock方法内new出来的对象
/****************************************************/
public boolean makeFile(String path) {
File file = new File(path);
return file.exists();
}
/****************************************************/
@RunWith(PowerMockRunner.class) // 告诉JUnit使用PowerMockRunner进行测试
@PrepareForTest({MockUtil.class, MockServiceImpl.class}) // 所有需要测试的类列在此处,适用于模拟final类或有final, private, static, native方法的类
@PowerMockIgnore("javax.management.*") //为了解决使用powermock后,提示classloader错误
public class MockExample {
// 将@Mock注解的示例注入进来
@InjectMocks
private MockServiceImpl mockService;
@Test
public void testNewObject() throws Exception {
File file = PowerMockito.mock(File.class);
PowerMockito.whenNew(File.class).withArguments("abc").thenReturn(file);
PowerMockito.when(file.exists()).thenReturn(true);
Assert.assertTrue(mockService.makeFile("abc"));
}
}
4.不让测试数据进入数据库(关键点:)
不让测试数据进入数据库的关键点:@Transactional、@Rollback(true)
Test用例:
import com.alibaba.fastjson.JSON;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.mockito.internal.util.MockUtil;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PowerMockIgnore;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.springframework.test.annotation.Rollback;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
import org.springframework.transaction.annotation.Transactional;
import javax.annotation.Resource;
import java.util.Random;
/**
* PowerMock是一个Java模拟框架,用于解决测试问题。
* 举个例子,你在使用Junit进行单元测试时,并不想让测试数据进入数据库,怎么办?这个时候就可以使用PowerMock,拦截数据库操作,并模拟返回参数。
*/
@RunWith(SpringJUnit4ClassRunner.class)
@PrepareForTest({MockUtil.class})
@PowerMockIgnore("javax.management.*")
@Transactional
@ContextConfiguration(locations = {"classpath*:applicationContext.xml"})
public class DemoMockTest {
//将@Mock注解的示例注入进来
@Resource
@InjectMocks
private DemoService demoService;
@Mock
private SingleService singleService;
public int randomNum(int min, int max) {
Random random = new Random();
int s = random.nextInt(max) % (max - min + 1) + min;
return s;
}
/**
* singleSequenceService服务mock,mock结果为ID值
*/
@Before
public void testInsertMockSuccess() {
Random random = new Random();
long id = random.nextInt(999999) % (1000000);
MockitoAnnotations.initMocks(this);
PowerMockito.when(singleService.getId("demo")).thenReturn(id);
}
@Rollback(true)
@Test
public void insert() {
Demo demo = new Demo();
demo.setSellerName("AA技术有限公司");
demo.setSellerNo("10000");
demoService.insert(demo);
}
@Test
public void getDemo() {
Demo demo = demoService.getDemo(1L);
System.out.println(JSON.toJSONString(demo));
}
}
demoService实现:
/**
* Demo
*/
@Service("demoService")
public class DemoServiceImpl implements DemoService {
@Resource
private DemoManager demoManager;
@Resource
private SingleService singleService;
@Override
public void insert(Demo demo) {
//唯一ID生成(分库分表)
long id = singleService.getId("demo");
demo.setId(id);
demoManager.insert(demo);
}
}