该文章已同步至个人微信公众号[不能止步],欢迎关注。
1. 问题场景
在写单元测试时,难免会遇到需要Mock的静态方法。当使用Spock测试框架时,Spock提供Moc静态方法Mock只支持Groovy语言,无法支持Java语言实现的静态方法Mocking Static Methods。
2. 解决方案
基于Spock测试框架的单元测试可以使用PowerMock或Mockito Mock静态方法。目前
spock-1.x mock静态方法使用的是powermock,2.x之后使用Mockito-3.4及更新版本。
3. 实现步骤
由于作者采用的是Spock 2.1-groovy-3.0,因此接下来的实现步骤是基于Mockito的。
- 步骤1:Gradle引入依赖
// 引入Spock测试框架
testImplementation("org.codehaus.groovy:groovy:3.0.9")
testImplementation("org.spockframework:spock-bom:2.1-groovy-3.0")
testImplementation("org.spockframework:spock-core:2.1-groovy-3.0")
testImplementation("org.spockframework:spock-spring:2.1-groovy-3.0")
testImplementation("org.spockframework:spock-junit4:2.1-groovy-3.0")
//引入Mockit
testImplementation("org.mockito:mockito-core:4.3.1")
testImplementation("org.mockito:mockito-inline:4.3.1")
- 步骤2:Mock静态方法
静态方法示例:
public class IDGenerator {
public static String nextId() {
//通过网络获得ID
String id = "xxxxx";
return id;
}
}
@Getter
@Setter
public class StudentPO {
private String id;
private String name;
private String code;
public static Student create(String name, String code) {
setId(IDGenerator.nextId());
setName(name);
setCode(code);
}
}
这里边由于IDGenerator通过网络获得唯一ID(如分布式ID中心),因此为了提高单元测试的效率,需要Mock IDGenerator。
// 使用Groovy语言开发
class StudentTest extends Specification {
Mockito.mockStatic(IDGenerator.class)
def "should success when create student"() {
given:
var name = "tester"
var code = "123456"
Mockito.when(IDGenerator.nextId()).thenReturn("123456789")
when:
var student = Student.create(name, code)
then:
student.getId() == "123456789"
}
}
4. FAQ
- static mock is already registered in the current thread
原因分析:在运行测试用例的线程中Mock同一个静态方法多次
解决方案:
// groovy语言编写
class StudentTest extends Specification {
MockedStatic<IDGenerator> generator
def setup() {
generator = Mockit.mockStatic(IDGenerator.class)
}
// 测试用例
def cleanup() {
// 清除Mock的静态方法
generator.close()
}
}