Spock Mock with Guava 系列
Spock Mock with Guava Collection
我在尝试模拟 Guava 集合中的依赖项时遇到困难。
假设我要测试以下代码:
@Service
public final class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public Collection<String> runAll(Collection<String> dataList) {
final ImmutableList.Builder<String> builder = ImmutableList.builder();
for (String data : dataList) {
builder.add(serviceB.run(data));
}
return builder.build();
}
}
我的 Spock 规格如下所示:
class ServiceASpec extends Specification {
def serviceB = Mock(ServiceB.class)
def serviceA = new ServiceA(serviceB)
def "test"() {
when:
def strings = serviceA.runAll(['data1', 'data2'])
then:
1 * serviceB.run('data1') >> 'result1'
1 * serviceB.run('data2') >> 'result2'
0 * _._
strings == ['result1', 'result2']
}
}
这个规范运行得很好,它正在做我想要它做的事情。
然后我重构了我的实现以使用 Guava 的 Collections2.transform(..)
:-
@Service
public final class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public Collection<String> runAll(Collection<String> dataList) {
return Collections2.transform(dataList, new Function<String, String>() {
@Override
public String apply(final String input) {
return serviceB.run(input);
}
});
}
}
当我重新运行规范时,出现此错误:-
Too few invocations for:
1 * serviceB.run('data1') >> 'result1' (0 invocations)
Unmatched invocations (ordered by similarity):
None
Too few invocations for:
1 * serviceB.run('data2') >> 'result2' (0 invocations)
Unmatched invocations (ordered by similarity):
None
我的看法是它与模拟时间有关,因为 Guava 函数只会在使用集合时执行。
但是,我不确定如何重构我的规范以使其正常工作。
我该如何解决这个问题?谢谢。
在幕后 transform()
method returns TransformedCollection
class. As you can see here 转换在迭代包装集合时立即应用。由于您不迭代转换后的集合模拟服务,因此不会调用并且不会记录任何交互。
似乎简单地迭代集合应该可以解决问题,但是这样的测试应该有很好的记录。
另一种方法是使用 FluentIterable.from(list).transform(function).toList()
而不是 Collections2.transform(list, function)
。
我在尝试模拟 Guava 集合中的依赖项时遇到困难。
假设我要测试以下代码:
@Service
public final class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public Collection<String> runAll(Collection<String> dataList) {
final ImmutableList.Builder<String> builder = ImmutableList.builder();
for (String data : dataList) {
builder.add(serviceB.run(data));
}
return builder.build();
}
}
我的 Spock 规格如下所示:
class ServiceASpec extends Specification {
def serviceB = Mock(ServiceB.class)
def serviceA = new ServiceA(serviceB)
def "test"() {
when:
def strings = serviceA.runAll(['data1', 'data2'])
then:
1 * serviceB.run('data1') >> 'result1'
1 * serviceB.run('data2') >> 'result2'
0 * _._
strings == ['result1', 'result2']
}
}
这个规范运行得很好,它正在做我想要它做的事情。
然后我重构了我的实现以使用 Guava 的 Collections2.transform(..)
:-
@Service
public final class ServiceA {
private final ServiceB serviceB;
@Autowired
public ServiceA(ServiceB serviceB) {
this.serviceB = serviceB;
}
public Collection<String> runAll(Collection<String> dataList) {
return Collections2.transform(dataList, new Function<String, String>() {
@Override
public String apply(final String input) {
return serviceB.run(input);
}
});
}
}
当我重新运行规范时,出现此错误:-
Too few invocations for:
1 * serviceB.run('data1') >> 'result1' (0 invocations)
Unmatched invocations (ordered by similarity):
None
Too few invocations for:
1 * serviceB.run('data2') >> 'result2' (0 invocations)
Unmatched invocations (ordered by similarity):
None
我的看法是它与模拟时间有关,因为 Guava 函数只会在使用集合时执行。
但是,我不确定如何重构我的规范以使其正常工作。
我该如何解决这个问题?谢谢。
在幕后 transform()
method returns TransformedCollection
class. As you can see here 转换在迭代包装集合时立即应用。由于您不迭代转换后的集合模拟服务,因此不会调用并且不会记录任何交互。
似乎简单地迭代集合应该可以解决问题,但是这样的测试应该有很好的记录。
另一种方法是使用 FluentIterable.from(list).transform(function).toList()
而不是 Collections2.transform(list, function)
。