MissingPropertyException in Spock test - java

I have problem with test written in groovy (using Spock as a framework). While I try fetch property in then block and then use it in interaction I receive No such property: updatedValue for class: my.test.class.MyTestClass on the interaction with event publisher. Can anyone tell why is that?
class MyTestClass extends Specification {
#Autowired
private MyClass sut
#Autowired
private MyClassRepository myClassRepository
#SpringBean
private EventPublisher eventPublisher = Mock()
def "Should do something"() {
given:
//some data
def someId = "someId"
def event = new SomeEventObject()
when:
sut.handle(event)
then:
def updatedValue = myClassRepository.findTestClass(someId)
updatedTestClass.cash == 100
1 * eventPublisher.publishEvent(new SomeNextEvent(updatedValue))
}
}

You are encountering a side-effect of Spock's magic.
Your method basically gets transformed to this:
public void $spock_feature_0_0() {
org.spockframework.runtime.ErrorCollector $spock_errorCollector = org.spockframework.runtime.ErrorRethrower.INSTANCE
org.spockframework.runtime.ValueRecorder $spock_valueRecorder = new org.spockframework.runtime.ValueRecorder()
java.lang.Object someId = 'someId'
java.lang.Object event = new apackage.SomeEventObject()
this.getSpecificationContext().getMockController().enterScope()
this.getSpecificationContext().getMockController().addInteraction(new org.spockframework.mock.runtime.InteractionBuilder(25, 9, '1 * eventPublisher.publishEvent(new SomeNextEvent(updatedValue))').setFixedCount(1).addEqualTarget(eventPublisher).addEqualMethodName('publishEvent').setArgListKind(true, false).addEqualArg(new apackage.SomeNextEvent(updatedValue)).build())
sut.handle(event)
this.getSpecificationContext().getMockController().leaveScope()
java.lang.Object updatedValue = myClassRepository.findTestClass(someId)
try {
org.spockframework.runtime.SpockRuntime.verifyCondition($spock_errorCollector, $spock_valueRecorder.reset(), 'updatedTestClass.cash == 100', 23, 13, null, $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(3), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(1), $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(0), updatedTestClass).cash) == $spock_valueRecorder.record($spock_valueRecorder.startRecordingValue(2), 100)))
}
catch (java.lang.Throwable throwable) {
org.spockframework.runtime.SpockRuntime.conditionFailedWithException($spock_errorCollector, $spock_valueRecorder, 'updatedTestClass.cash == 100', 23, 13, null, throwable)}
finally {
}
this.getSpecificationContext().getMockController().leaveScope()
}
If you look closely, you can see that the interaction definition was moved before the when block, but the findTestClass() call stayed behind.
that is why you get the missing property exception.
The solution is to either move the lookup to the given block, or if that is not possible, to use argument capturing and then check afterwards.
given:
def capturedEvent
when:
...
then:
1 * eventPublisher.publishEvent(_) >> { capturedEvent = it[0} }
and:
def updatedValue = myClassRepository.findTestClass(someId)
capturedEvent instanceof SomeNextEvent
capturedEvent.value == updatedValue
You can take a look at the transformed code yourself in the groovy web console by clicking on Inspect AST.

Related

Chained creational OOP design pattern problem

I am creating a class that is responsible for validating a configuration. This class calls other classes that validate said config by creating new instances in the form of a chain. At first glance, the code structure looks horrible, but It works. Anyway, I think it's not the best way to handle this logic.
I leave here a simplified version of the code in TypeScript, but I also leave it in Python and Java for reference only:
class Validator {
private _notValidatedConfig: NotValidatedConfig
constructor(notValidatedConfig: NotValidatedConfig) {
this._notValidatedConfig = notValidatedConfig
}
validateConfig(): ValidatedConfig {
return (
new Phase4Validation(
new Phase3Validation(
new Phase2Validation(
new Phase1Validation(
this._notValidatedConfig
).validate()
).validate()
).validate()
).validate()
)
}
// Alternative
validateConfig2(): ValidatedConfig {
const validatedPhase1Config: ValidatedPhase1Config = new Phase1Validation(this._notValidatedConfig).validate()
const validatedPhase2Config: ValidatedPhase2Config = new Phase2Validation(validatedPhase1Config).validate()
const validatedPhase3Config: ValidatedPhase3Config = new Phase3Validation(validatedPhase2Config).validate()
const validatedPhase4Config: ValidatedPhase4Config = new Phase4Validation(validatedPhase3Config).validate()
return validatedPhase4Config;
}
}
Python
Java Disclaimer: I don't have any experience with Java, so maybe there are some syntax errors.
The "alternative" is the same code, but not directly chained, instead, for every validation, it's creating a new variable.
I think the "alternative" is more readable but performs worse.
What do you think about this code? what did you change? How would you face this problem or with what design pattern or framework? (programming language doesn't matter for these question)
I would create a base class Validation and just create derived classes from it if it is necessary to add new validation:
public abstract class Validation
{
public Validation(string config)
{
}
public abstract string Validate();
}
and its concrete implementations:
public class Phase1Validation : Validation
{
public Phase1Validation(string config) : base(config)
{}
public override string Validate()
{
if (true)
return null;
return "There are some errors Phase1Validation";
}
}
public class Phase2Validation : Validation
{
public Phase2Validation(string config) : base(config)
{
}
public override string Validate()
{
if (true)
return null;
return "There are some errors in Phase2Validation";
}
}
and then just create a list of validators and iterate through them to find errors:
public string Validate()
{
List<Validation> validations = new List<Validation>()
{
new Phase1Validation("config 1"),
new Phase2Validation("config 2")
};
foreach (Validation validation in validations)
{
string error = validation.Validate();
if (!string.IsNullOrEmpty(error))
return error;
}
return null; // it means that there are no errors
}
UPDATE:
I've little bit edited my classes to fit your new question requirements:
validations should be ordered. Added Order property
get config from previous validation and send it to the next validation
It can be seen that this approach allows to avoid to write nested classes like this:
new Phase4Validation(
new Phase3Validation(
new Phase2Validation(...).validate()
).validate()
).validate()
So you can add new classes without editing validation classes and it helps to keep Open CLosed Principle of SOLID principles.
So the code looks like this:
Abstractions:
public abstract class Validation
{
// Order to handle your validations
public int Order { get; set; }
// Your config file
public string Config { get; set; }
public Validation(int order)
{
Order = order;
}
// "virtual" means that method can be overriden
public virtual string Validate(string config)
{
Config = config;
if (true)
return null;
return "There are some errors Phase1Validation";
}
}
And its concrete implementations:
public class Phase1Validation : Validation
{
public Phase1Validation(int order) : base(order)
{
}
}
public class Phase2Validation : Validation
{
public Phase2Validation(int order) : base(order)
{
}
}
And method to validate:
string Validate()
{
List<Validation> validations = new List<Validation>()
{
new Phase1Validation(1),
new Phase2Validation(2)
};
validations = validations.OrderBy(v => v.Order).ToList();
string config = "";
foreach (Validation validation in validations)
{
string error = validation.Validate(config);
config = validation.Config;
if (!string.IsNullOrEmpty(error))
return error;
}
return null; // it means that there are no errors
}
I leave here my own answer, but I'm not going to select it as correct because I think there exist better answers (besides the fact that I am not very convinced of this implementation).
A kind of Decorator design pattern allowed me to do chain validation with greater use of the dependency injection approach.
I leave here the code but only for Python (I have reduced the number of phases from 4 to 2 to simplify the example).
from __future__ import annotations
import abc
from typing import cast
from typing import Any
from typing import TypedDict
NotValidatedConfig = dict
ValidatedConfig = TypedDict("ValidatedConfig", {"foo": Any, "bar": Any})
class InvalidConfig(Exception):
...
# This class is abstract.
class ValidationHandler(abc.ABC):
_handler: ValidationHandler | None
def __init__(self, handler: ValidationHandler = None):
self._handler = handler
# This method is abstract.
#abc.abstractmethod
def _validate(self, not_validated_config: NotValidatedConfig):
...
def _chain_validation(self, not_validated_config: NotValidatedConfig):
if self._handler:
self._handler._chain_validation(not_validated_config)
self._validate(not_validated_config)
def get_validated_config(self, not_validated_config: NotValidatedConfig) -> ValidatedConfig:
self._chain_validation(not_validated_config)
# Here we convert (in a forced way) the type `NotValidatedConfig` to
# `ValidatedConfig`.
# We do this because we already run all the validations chain.
# Force a type is not a good way to deal with a problem, and this is
# the main downside of this implementation (but it works anyway).
return cast(ValidatedConfig, not_validated_config)
class Phase1Validation(ValidationHandler):
def _validate(self, not_validated_config: NotValidatedConfig):
if "foo" not in not_validated_config:
raise InvalidConfig('Config miss "foo" attr')
class Phase2Validation(ValidationHandler):
def _validate(self, not_validated_config: NotValidatedConfig):
if not isinstance(not_validated_config["foo"], str):
raise InvalidConfig('"foo" must be an string')
class Validator:
_validation_handler: ValidationHandler
def __init__(self, validation_handler: ValidationHandler):
self._validation_handler = validation_handler
def validate_config(self, not_validated_config: NotValidatedConfig) -> ValidatedConfig:
return self._validation_handler.get_validated_config(not_validated_config)
if __name__ == "__main__":
# "Pure Dependency Injection"
validator = Validator((Phase2Validation(Phase1Validation())))
validator.validate_config({"foo": 1, "bar": 1})
What is the problem with this approach?: the lightweight way in which the types are concatenated. In the original example, the Phase1Validation generates a ValidatedPhase1Config, which is safely used by the Phase2Validation. With this implementation, each decorator receives the same data type to validate, and this creates safety issues (in terms of typing). The Phase1Validation gets NotValidatedConfig, but the Phase2Validation can't use that type to do the validation, they need the Phase1Validation.

How to mock service class injections in Spock testing framework?

I have a Java service which has few things injected by Guice.
public class RecoveryServiceImpl implements RecoveryService {
#Inject
public RecoveryServiceImpl(SessionInstanceCache sessionInstanceCache, AttendeeCache attendeeCache, MessagingStreamConfiguration messagingConfig) {
this.sessionInstanceCache = sessionInstanceCache;
this.attendeeCache = attendeeCache;
this.messagingConfig = messagingConfig;
}
#Override
public SessionInstanceData recoverSessionInstance(SessionInstanceDto sessionInstance) {
SessionInstanceData sessionInstanceData = SessionInstanceHelper.recoverSessionInstance(sessionInstance);
if (sessionInstanceData.getDeepstreamServerKey() == null) {
String dsKey = SessionInstanceHelper.pickRandomDeepstreamServerKey(
sessionInstanceData, messagingConfig);
And this does:
public static String pickRandomDeepstreamServerKey(
SessionInstanceData sessionInstanceData, MessagingStreamConfiguration dsConfig) {
// NPE occurs here
List<String> dsKeys = new ArrayList(dsConfig.getBaseUrls().keySet());
This is tested with Spock.
I added the messagingConfig and now I am struggling making it mocked in a Spock test:
class RecoveryServiceImplTest extends Specification {
...
MessagingStreamConfiguration msgConfig = Mock(MessagingStreamConfiguration);
RecoveryService recoveryService = new RecoveryServiceImpl(sessionInstanceCache, attendeeCache, msgConfig);
def "Recover session instance"() {
...
def dsMap = new HashMap<String, URL>();
dsMap.put("ds1", new URL("http://ilovemocking.com/"));
when:
msgConfig.getBaseUrls() >> dsMap;
//msgConfig.getBaseUrls().keySet() >> new HashSet(){{add("ds1")}};
recoveryService.recoverSessionInstance(sessionInstanceDto)
In the call to recoverSessionInstance(), I get a NPE because getBaseUrls() returns null.
I have tried other way, instantiating the msgConfig as a normal object (AKA "stubbing"), but same result.
How should I make Spock Mock to return the dsMap instead of null?
In the end, it was some issue with missing method in a dependency .jar (compared to what I saw as code). The NPE was coming from the Mock proxy rather than the expression itself. However it was hard to see in the stacktrace full of reflections.
I will delete the question in a while.

UnitTesting: how to pass my mock class in the read code

I am using hazelcast in my project and I want to unit test some function but i do not want it to connect to real hazelcast and perform test on it for that i created a custom mock class which simply uses scala map because in hazelcast maps also there
here is my code
trait UserRepository {
def getUserObj(id: String):Option[User]
def addToUserRepo(user: User)
}
class UserRepo extends UserRepository{
def getUserObj(id: String):Option[User] = {
val userMap = hcastClient.getMap[String, User]("UserMap")
val userObj = userMap.get(id)
Option(userObj)
}
def addToUserRepo(user: User) = {
val directUserMap: IMap[String, User] = hcastClient.getMap[String,User]("UserMap")
directUserMap.set(user.uuid, user)
}
and here i created a simple customized mocked version class where the functionality is same just; replaced it with scala map:
class UserRepoMock extends UserRepository {
val map:Map[String,User]=Map[String,User]()
def getUserMap:Map[String,User] = {
map
}
def getUserObj(id: String):User = {
val userMap = getUserMap
val userObj = userMap.get(id)
userObj
}
def addToUserRepo(user: User) = {
val userMap = getUserMap
userMap.put(user.uuid, user)
}
class UserUtil(userRepo:UserRepo) {
def addUser(user:User):Boolean={
try{
userRepo.addToUserRepo(user)
true
}
catch {
case e:Exception=>false
}
def getUser(id:String):User={
val user=userRepo.getUserObj(id)
user
}
Mow i want to unit test methods addUser and getUserof UserUtil class
by doing like this:
class UserUtilTest extends funSpec {
val userUtil=new UserUtil(new UserRepoMock)
userUtil.addUser //perform unit test on it
userUtil.getUser //perform unit test on it
// instead of doing this val userUtil=new UserUtil(new UserRepo)
}
but the compiler not allowing me to do that,there is something which i am missing, Please help me how can i achieve the desired functionality
This is the compiler error:
type mismatch; found : testhcastrepo.UserRepoMock required: com.repositories.UserRepo
Well: your utils class says:
class UserUtil(userRepo:UserRepo)
So it needs an instance of UserRepo.
But then your are passing an instance of UserRepoMock. A UserRepoMock is a UserRepository, as UserRepo is; but a UserRepoMock is not a UserRepo!
Probably it is as simple as changing the utils to
class UserUtil(userRepo:UserRepository)
to indicate that you don't want to specify a specific class. Instead you simply say: anything that has the trait will do!
Beyond that: the real answer might be: have a look at your naming habits. You see, those two names UserRepositor and UserRepo; they are pretty "close" to each other; and it is not at all clear, what the difference between the two is. If the names would be more distinct, like UserRepositoryTrait and HCastUserRepository you probably would not have made this mistake in the first place (not sure my suggestions are "good" names according to scala conventions; but they are just meant to give you an idea).

How to disallow dependencies via #Grab in Groovy script

I want to allow users to run their Groovy scripts in my Java server app, but I also want disallow them to use #Grab for adding any random dependencies.
Yes, I can simply cut off all #Grab annotations by search & replace in source code, but it will be better to do this in more elegant way, e.g. allow approved dependencies only.
And yes, I know that the best solution of this prob is JVM's SecurityManager.
There are various approaches, such as the Groovy Sandbox, which may work better than what you're about to see.
import groovy.grape.Grape
Grape.metaClass.static.grab = {String endorsed ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map args, Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
def source1 = '''
println('This is a nice safe Groovy script.')
'''
def source2 = '''
#Grab('commons-validator:commons-validator:1.4.1')
import org.apache.commons.validator.routines.EmailValidator
def emailValidator = EmailValidator.getInstance();
assert emailValidator.isValid('what.a.shame#us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')
println 'You should not see this message!'
'''
def script
def shell = new GroovyShell()
try {
script = shell.parse(source1)
script.run()
} catch (Exception e) {
assert false, "Oh, oh. That wasn't supposed to happen :("
}
try {
script = shell.parse(source2)
assert false, "Oh, oh. That wasn't supposed to happen :("
} catch (ExceptionInInitializerError e) {
println 'Naughty script was blocked when parsed.'
}
The example above demonstrates how to block #Grab. It does this not by blocking the annotation, but by overriding the method call added by the annotation: groovy.grape.Grape.grab().
Grape.metaClass.static.grab = {String endorsed ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Grape.metaClass.static.grab = {Map args, Map dependency ->
throw new SecurityException("Oh no you didn't! Grabbing is forbidden.")
}
Here's the naughty script dissected by the Groovy Console AST viewer:
#groovy.lang.Grab(module = 'commons-validator', group = 'commons-validator', version = '1.4.1')
import org.apache.commons.validator.routines.EmailValidator as EmailValidator
public class script1440223706571 extends groovy.lang.Script {
private static org.codehaus.groovy.reflection.ClassInfo $staticClassInfo
public static transient boolean __$stMC
public script1440223706571() {
}
public script1440223706571(groovy.lang.Binding context) {
super(context)
}
public static void main(java.lang.String[] args) {
org.codehaus.groovy.runtime.InvokerHelper.runScript(script1440223706571, args)
}
public java.lang.Object run() {
java.lang.Object emailValidator = org.apache.commons.validator.routines.EmailValidator.getInstance()
assert emailValidator.isValid('what.a.shame#us.elections.gov') : null
assert !(emailValidator.isValid('an_invalid_emai_address')) : null
return null
}
static {
groovy.grape.Grape.grab([:], ['group': 'commons-validator', 'module': 'commons-validator', 'version': '1.4.1'])
}
protected groovy.lang.MetaClass $getStaticMetaClass() {
}
}
Here you can see the call to Grape.grab() in the static initializer. To add fine-grained filtering of dependencies, you can introspect the dependency and endorsed parameters.
dependency
['group': 'commons-validator', 'module': 'commons-validator', 'version': '1.4.1']
endorsed
commons-validator:commons-validator:1.4.1
Revised Implementation
This new implementation uses an Interceptor to block/allow Grape grabs.
import groovy.grape.GrapeIvy
def source1 = '''
println('This is a nice safe Groovy script.')
'''
def source2 = '''
#Grab('commons-validator:commons-validator:1.4.1')
import org.apache.commons.validator.routines.EmailValidator
def emailValidator = EmailValidator.getInstance();
assert emailValidator.isValid('what.a.shame#us.elections.gov')
assert !emailValidator.isValid('an_invalid_emai_address')
println 'You should not see this message!'
'''
def script
def shell = new GroovyShell()
def proxy = ProxyMetaClass.getInstance(GrapeIvy)
proxy.interceptor = new GrapeInterceptor({group, module, version ->
if(group == 'commons-validator' && module == 'commons-validator') false
else true
})
proxy.use {
shell.parse(source1).run()
try {
shell.parse(source2).run()
} catch (org.codehaus.groovy.control.MultipleCompilationErrorsException e) {
assert e.message.contains('unable to resolve class')
}
}
#groovy.transform.TupleConstructor
class GrapeInterceptor implements Interceptor {
private boolean invokeMethod = true
Closure authorizer
def afterInvoke(Object object, String methodName, Object[] arguments, Object result) {
invokeMethod = true
return result
}
def beforeInvoke(Object object, String methodName, Object[] arguments) {
if(methodName == 'createGrabRecord') {
def dependencies = arguments[0]
invokeMethod = authorizer(dependencies.group, dependencies.module, dependencies.version)
} else {
invokeMethod = true
}
return null
}
boolean doInvoke() { invokeMethod }
}
The GrapeInterceptor constructor takes a Closure as its only argument. With this Closure you can easily decide whether to allow the Grab to occur or not :)
For example, if the Grab looks like this: #Grab('commons-validator:commons-validator:1.4.1')
The Closure's arguments would be assigned as follows:
group: commons-validator
module: commons-validator
version: 1.4.1
To allow the Grab, the Closure must return true. Return false to block it.

Mutation not killed when it should be with a method with an auto-injected field

I have the following:
public class UnsetProperty extends Command {
#Resource
private SetProperty setProperty;
public String parse(String[] args) {
if (args.length != 4) {
throw new RuntimeException("Incorrect number of arguments. Expected 4. Got " + args.length);
}
String publisher = args[0];
String version = args[1];
String mode = args[2];
String property = args[3];
/*
* Unsetting a property is done by changing the current property to null.
* Technically, the old property doesn't get changed, a new one is inserted with
* a higher revision number, and it becomes the canonical one.
*/
setProperty.setProperty(publisher, version, mode, property, null, false);
return "";
}
}
and the following test:
public class UnsetPropertyTest extends CommandTest {
#Configuration
public static class Config {
#Bean(name = "mockSetProperty")
public SetProperty getSetProperty() {
return mock(SetProperty.class);
}
#Bean
public UnsetProperty getUnsetProperty() {
return new UnsetProperty();
}
}
#Resource
#InjectMocks
private UnsetProperty unsetProperty;
#Resource(name = "mockSetProperty")
private SetProperty setProperty;
// ... SNIP ...
#Test
public void testCallsSetPropertyWithCorrectParameters() throws SQLException, TaboolaException {
final String[] args = new String[]{"publisher", "version", "mode", "property"};
final String output = unsetProperty.parse(args);
verify(setProperty).setProperty("publisher", "version", "mode", "property", null, false);
// The above line should have killed the mutation!
verifyNoMoreInteractions(setProperty);
assertThat(output).isEqualTo("");
}
}
The test passes, as expected. When I run it through PIT I get the following result
33 1. removed call to my/package/SetProperty::setProperty → SURVIVED
Line #33 is highlighted in the class code.
The tests examined are as follows:
my.package.UnsetPropertyTest.testCallsSetPropertyWithCorrectParameters(my.package.UnsetPropertyTest)
(32 ms)
my.package.UnsetPropertyTest.testUnsetThrowsForIncorrectNumberOfParameters(my.package.UnsetPropertyTest)
(3 ms)
Now:
When I change the test invoke parameters (args) the test fails. As expected
When I change the assertion (verify(setProperty).setProperty(...)) arguments the test fails. As expected.
When I manually comment out the function call highlighted in the first code block, the test fails.
Why does the mutation survive?
I'm using Java 8, Mockito 1.9.5 and PIT 1.1.4.
Years later but no one seemed to mention that (Spring) #Resource and (Mockito) #InjectMocks are mutually exclusive solutions. You have multiple generated subclasses of UnsetProperty in play so PIT is simply confused about what's going on.

Categories