blob: 715c39326a977e06f2bc79fd7d1c31d5aa1b7fe4 [file] [log] [blame]
/*
* Copyright (c) 2016 Mockito contributors
* This program is made available under the terms of the MIT License.
*/
package org.mockito.internal.junit;
import org.mockito.stubbing.Stubbing;
import org.mockito.internal.invocation.finder.AllInvocationsFinder;
import org.mockito.internal.util.collections.ListUtil.Filter;
import org.mockito.invocation.Invocation;
import java.util.*;
import static org.mockito.internal.util.collections.ListUtil.filter;
/**
* Finds unused stubbings
*/
public class UnusedStubbingsFinder {
/**
* Gets all unused stubbings for given set of mock objects, in order
*/
public UnusedStubbings getUnusedStubbings(Iterable<Object> mocks) {
Set<Stubbing> stubbings = AllInvocationsFinder.findStubbings(mocks);
List<Stubbing> unused = filter(stubbings, new Filter<Stubbing>() {
public boolean isOut(Stubbing s) {
return s.wasUsed();
}
});
return new UnusedStubbings(unused);
}
/**
* Gets unused stubbings per location. This method is less accurate than {@link #getUnusedStubbings(Iterable)}.
* It considers that stubbings with the same location (e.g. ClassFile + line number) are the same.
* This is not completely accurate because a stubbing declared in a setup or constructor
* is created per each test method. Because those are different test methods,
* different mocks are created, different 'Invocation' instance is backing the 'Stubbing' instance.
* In certain scenarios (detecting unused stubbings by JUnit runner), we need this exact level of accuracy.
* Stubbing declared in constructor but realized in % of test methods is considered as 'used' stubbing.
* There are high level unit tests that demonstrate this scenario.
*/
public Collection<Invocation> getUnusedStubbingsByLocation(Iterable<Object> mocks) {
Set<Stubbing> stubbings = AllInvocationsFinder.findStubbings(mocks);
//1st pass, collect all the locations of the stubbings that were used
//note that those are _not_ locations where the stubbings was used
Set<String> locationsOfUsedStubbings = new HashSet<String>();
for (Stubbing s : stubbings) {
if (s.wasUsed()) {
String location = s.getInvocation().getLocation().toString();
locationsOfUsedStubbings.add(location);
}
}
//2nd pass, collect unused stubbings by location
//If the location matches we assume the stubbing was used in at least one test method
//Also, using map to deduplicate reported unused stubbings
// if unused stubbing appear in the setup method / constructor we don't want to report it per each test case
Map<String, Invocation> out = new LinkedHashMap<String, Invocation>();
for (Stubbing s : stubbings) {
String location = s.getInvocation().getLocation().toString();
if (!locationsOfUsedStubbings.contains(location)) {
out.put(location, s.getInvocation());
}
}
return out.values();
}
}