Spring 结合 Mockito 编写单元测试讲到可以用 Mockito 模拟类/对象的行为,让我们只关心和测试自己的业务逻辑。
但是 Mockito 不支持给静态方法打桩,PowerMock 可以弥补这个不足。
关于 Mockito 的具体使用方法可以参考 Mocktio 入门。
我们用一个示例说明 Spring 中如何使用 PowerMock mock静态方法。
示例
项目结构
.
├── build.gradle
├── settings.gradle
└── src
├── main
│ ├── java
│ │ └── demo
│ │ ├── AppConfig.java
│ │ ├── BusinessService.java
│ │ ├── HttpService.java
│ │ └── Main.java
│ └── resources
└── test
└── java
└── demo
└── BusinessServiceTest.java
build.gradle
build.gradle 中声明的依赖如下:
dependencies {
compile group: 'org.springframework', name: 'spring-context', version: '5.0.6.RELEASE'
testCompile group: 'org.springframework', name: 'spring-test', version: '5.0.6.RELEASE'
testCompile group: 'junit', name: 'junit', version: '4.12'
testCompile group: 'org.mockito', name: 'mockito-core', version: '2.25.1'
// PowerMock 相关依赖
testCompile group: 'org.powermock', name: 'powermock-core', version: '2.0.0'
testCompile group: 'org.powermock', name: 'powermock-module-junit4', version: '2.0.0'
testCompile group: 'org.powermock', name: 'powermock-api-mockito2', version: '2.0.0'
}
src/main/java/demo 中是一个简单的 Spring 项目,各个类的内容如下:
HttpService.java
package demo;
import java.util.Random;
public class HttpService {
public static int queryStatus() { // 注意,这个特定声明为了静态方法
// 发起网络请求,得到响应值,然后返回
// 这里用随机数模拟
return new Random().nextInt(2);
}
}
BusinessService.java
package demo;
import org.springframework.stereotype.Service;
@Service
public class BusinessService {
public String hello() {
int status = HttpService.queryStatus();
if (status == 0) {
return "你好";
}
else {
return "Hello";
}
}
}
AppConfig.java
package demo;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
@Configuration
@ComponentScan
public class AppConfig {
}
Main.java
package demo;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class Main {
public static void main(String[] args) {
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
BusinessService businessService = applicationContext.getBean(BusinessService.class);
System.out.println(businessService.hello()); // 输出"你好",或者"Hello"
}
}
src/test/java/demo 编写了两个关于 BusinessService 的测试类。
测试示例
BusinessServiceTest 测试类内容如下:
package demo;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.modules.junit4.PowerMockRunnerDelegate;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(PowerMockRunner.class) // 必选
@PowerMockRunnerDelegate(SpringJUnit4ClassRunner.class) // 必选
@PrepareForTest(HttpService.class) // 必选
@ContextConfiguration(classes=AppConfig.class)
public class BusinessServiceTest {
@Autowired
private BusinessService businessService;
@Test
public void testHello() {
PowerMockito.mockStatic(HttpService.class); // 必选
// 打桩
Mockito.when(HttpService.queryStatus()).thenReturn(0);
// 测试
Assert.assertEquals("你好", businessService.hello()); // 永远都返回 "你好"
}
}
@PrepareForTest 中声明要mock的静态方法所在的类,可以声明多个,比如:
@PrepareForTest({HttpService.class, HttpService2.class})