com.blogspot.toomuchcoding.spock.subjcollabs.SetterInjector.groovy Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of spock-subjects-collaborators-extension Show documentation
Show all versions of spock-subjects-collaborators-extension Show documentation
Spock extension that allows you to inject Collaborators into Subjects. Bases on Mockito's @InjectMocks functionality
package com.blogspot.toomuchcoding.spock.subjcollabs
import groovy.transform.PackageScope
import org.spockframework.runtime.model.FieldInfo
import spock.lang.Specification
import java.lang.reflect.Field
import java.lang.reflect.Method
@PackageScope
class SetterInjector extends NonConstructorBasedInjector {
private static final List SETTERS_TO_IGNORE = ["setMetaClass"]
SetterInjector(FieldRetriever fieldRetriever) {
super(fieldRetriever)
}
@Override
boolean tryToInject(Collection injectionCandidates, Specification specInstance, FieldInfo fieldInfo) {
// Property setter injection; mocks will first be resolved by type, then, if there is several property of the same type
try {
Object subject = instantiateSubjectAndSetOnSpecification(specInstance, fieldInfo)
List setters = getAllSettersFromSubject(fieldInfo)
Map matchingSetters = getMatchingSettersBasingOnTypeAndPropertyName(injectionCandidates, setters)
if (matchingSetters.isEmpty()) {
return false
}
Map fields = fieldRetriever.getAllUnsetFields(injectionCandidates, fieldInfo, subject)
matchingSetters.each { Method method, Field injectionCandidate ->
if (fields.containsValue(injectionCandidate)) {
method.invoke(subject, specInstance[injectionCandidate.name])
}
}
return true
} catch (Exception e) {
return false
}
}
private Map getMatchingSettersBasingOnTypeAndPropertyName(Collection injectionCandidates, List setters) {
Map matchingSetters = [:]
injectionCandidates.each { Field injectionCandidate ->
setters.each {
if (it.genericParameterTypes.size() == 1 && it.genericParameterTypes[0] == injectionCandidate.type) {
// if there is several property of the same type by the match of the property name and the mock name.
if (matchingSetters[it] && it.name.substring(3).equalsIgnoreCase(injectionCandidate.name)) {
matchingSetters[it] = injectionCandidate
} else if (!matchingSetters[it]) {
matchingSetters[it] = injectionCandidate
}
}
}
}
return matchingSetters
}
private List getAllSettersFromSubject(FieldInfo fieldInfo) {
return fieldInfo.type.methods.findAll {
return it.name.startsWith("set") && !SETTERS_TO_IGNORE.contains(it.name)
}
}
}