Reputation: 40176
I'm having difficulties trying to mock a dependency within Guava Collection.
Let's assume I have a following code to test:
@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();
}
}
My Spock Spec looks like this:
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']
}
}
This spec runs just fine and it is doing what I want it to do.
Then I refactored my implementation to use Guava's 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);
}
});
}
}
When I rerun my spec, I'm getting this error:-
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
My take is it has something to do with the mocking timing because the Guava function will only be executed when the collection is used.
However, I wasn't sure how to refactor my spec to make this to work.
How do I go about solving this? Thanks.
Upvotes: 1
Views: 321
Reputation: 84854
Under the hood transform()
method returns TransformedCollection
class. As you can see here transformation is applied no sooner than on iterating the wrapped collection. Since you don't iterate the transformed collection mocked service is not invoked and no interaction is recorded.
It seems that simply iterating the collection should solve the problem, however such test should be really well documented.
Another way is using FluentIterable.from(list).transform(function).toList()
instead of Collections2.transform(list, function)
.
Upvotes: 3