I have a SpringBootTest that reads in properties from application.properties. The setup code uses the #Value annotation to set the values accordingly. One of these properties is an array of names.
I am trying to write a data driven test using Spock. The where statement is using these names that are initialized in the setup:
expect:
retrievedName == value
where:
value << getNames()
This always fails with org.spockframework.runtime.SpockExecutionException: Data provider is null.
It appears that the getNames() call is invoked before the properties are initialized in the setup code. If I do not use the where statement (data driven testing), all works fine. Is there a workaround for this?
You cannot use data initialized in the setup section as a source for data driven tests. As per the docs:
Although it is declared last, the where block is evaluated before the feature method containing it runs.
You can try and use setupSpec() methods and #Shared fields as a workaround.
See here for an example.
In Thread Group #1 I have a Regular Expression with Match Number set to -1 and I want to use the complete variable in Thread Group #2.
I am currently able to share normal variables using props.put but I am not able to share the complete array to then obtain the values using __V function on Thread Group #2.
Is this feasible?
Just add JSR223 PostProcessor (make sure it goes after Regular Expression Extractor) and use the following code:
vars.entrySet().each { var ->
if (var.getKey().startsWith('foo')) {
props.put(var.getKey(), var.getValue())
}
}
In another Thread Group you can convert properties into variables using the same approach:
props.entrySet().each {prop ->
if (prop.getKey().startsWith('foo')){
vars.put(prop.getKey(),prop.getValue())
}
}
Just replace foo with your variable reference name and that would be it.
You can find information regarding Groovy scripting in JMeter in Apache Groovy - Why and How You Should Use It guide if needed.
TestPlan Thread Group HTTP Request1 ->Regular Expression Extractor - Return 10 Results - URLs -- Single Thread
ForEach Controller - Using variable from extractor - Successfully Loops through above results HTTP Request2 ->Regular Expression Extractor - Return 10 Results
This above is under 1 thread
I want to have ForEach Controller under different thread --run multiple therads and use the URLs extracted from 1 thread HTTP Sampler -- I tried to use these two approaches
https://www.blazemeter.com/blog/knit-one-pearl-two-how-use-variables-different-thread-groups
How do I pass a variable from one Thread Group to another in JMeter
but somehow now managed it to work
Please help
ForEach Controller will not work with JMeter Properties, it is designed to work only with JMeter Variables so if you want to pass them between different Thread Groups you will need to do some scripting.
Add JSR223 PostProcessor after the Regular Expression Extractor and put the following code into "Script" area
vars.entrySet().each { var ->
if (var.getKey().startsWith('foo')) {
props.put(var.getKey(), var.getValue())
}
}
replace foo with what you have as a Reference Name in the Regular Expression Extractor. The above code will convert all variables which names start with foo into the relevant JMeter Properties
Add Test Action sampler to the second Thread Group (you don't need to measure time of properties to variables conversion, do you)
Add JSR223 PreProcessor as a child of the Test Action sampler
Put the following code into "Script" area
props.entrySet().each {prop ->
if (prop.getKey().startsWith('foo')){
vars.put(prop.getKey(),prop.getValue())
}
}
the above code convert JMeter Properties into JMeter Variables so you will be able to use them in the ForEach Controller in the second Thread Group. Again, replace this foo with the reference name of your own variable.
See Apache Groovy - Why and How You Should Use It article for more information on using Groovy scripting in JMeter tests
Is there a possibility to have variables that depend on the listener where there lay in?
So I want to execute two samplers which are working with a JSR223 Assertion. I use a groovy code which asks for the value of the variable "name". If I execute Sampler A it should say "Tom" and if i execute Sampler B it should say "Paul".
It has to be possible to execute both at the same time.
You have sampler shorthand in the JSR223 Assertion which stands for this or that Sampler. So you can check its name by calling sampler.getName() function which will basically execute underlying AbstractTestElement.getName() method. The relevant code would look like:
if (sampler.getName().equals('Sampler A')) {
log.info('Tom')
}
else if (sampler.getName().equals('Sampler B')) {
log.info('Paul')
}
You can set a JMeter Variable from Groovy code using vars shorthand which in its turn stands for JMeterVariables class instance like:
vars.put('foo', 'bar')
Once done you will be able to refer created variable as ${foo} where required - it will have the value of bar
Check out Scripting JMeter Assertions in Groovy - A Tutorial article for more details.
when I use spring cache with redis, I use it in two app, the one read and write,the other is only read,how can I config?
I try do like this, but it does not work!
#Cacheable(value = "books", key = "#isbn", condition = "false")
Can anyone help ?
You have misunderstood the purpose of the #Cacheable annotation's "condition" attribute. Per the documentation...
If true, the method is cached - if not, it behaves as if the method is
not cached, that is executed every since time no matter what values
are in the cache or what arguments are used.
The condition attribute just determines whether the cache (e.g. Redis) is consulted first, before executing the (potentially expensive) method. If condition evaluates to false, then the method will always be executed and the result subsequently cached.
In the read-only app, I am assuming you want the cache consulted first, if the value is not in the cache, then execute the method, however, DO NOT cache the result. Is this correct?
If so, then you only need specify the unless attribute instead of the condition attribute like so...
#Cacheable(value="books", key="#isbn", unless="true")
void someBookMutatingOperation(String isbn, ...) { .. }
If, however, you want to avoid the cacheable method invocation in the read-only (version of the) app altogether and just consult the cache regardless of whether a value actually exists in the cache or not, then your problem is quite a bit more complex/difficult.
Spring's Cache Abstraction operates on the premise that if a value is not in the cache then it will return null to indicate a cache miss, which is then followed by a subsequent method invocation. Only when a cache returns a value for the specified key(s) will the method invocation be avoided.
Without a custom extension (perhaps using (additional) AOP interceptors) there is no way to avoid the OOTB behavior.
I will not elaborate on this later technique unless your use case requires it.
Hope this helps.
#John Blum
thanks! happy new year.
your answer inspired me, I have read a part of the spring cache source code. the CacheInterceptor class. the CacheAspectSupport class.
private Object execute(CacheOperationInvoker invoker, CacheOperationContexts contexts) {
// Process any early evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), true, ExpressionEvaluator.NO_RESULT);
// Check if we have a cached item matching the conditions
Cache.ValueWrapper cacheHit = findCachedItem(contexts.get(CacheableOperation.class));
// Collect puts from any #Cacheable miss, if no cached item is found
List<CachePutRequest> cachePutRequests = new LinkedList<CachePutRequest>();
if (cacheHit == null) {
collectPutRequests(contexts.get(CacheableOperation.class), ExpressionEvaluator.NO_RESULT, cachePutRequests);
}
Cache.ValueWrapper result = null;
// If there are no put requests, just use the cache hit
if (cachePutRequests.isEmpty() && !hasCachePut(contexts)) {
result = cacheHit;
}
// Invoke the method if don't have a cache hit
if (result == null) {
result = new SimpleValueWrapper(invokeOperation(invoker));
}
// Collect any explicit #CachePuts
collectPutRequests(contexts.get(CachePutOperation.class), result.get(), cachePutRequests);
// Process any collected put requests, either from #CachePut or a #Cacheable miss
for (CachePutRequest cachePutRequest : cachePutRequests) {
cachePutRequest.apply(result.get());
}
// Process any late evictions
processCacheEvicts(contexts.get(CacheEvictOperation.class), false, result.get());
return result.get();
}
I think should prevent the cachePutRequest execute. if no cache be hit, to invoke the method body of #Cacheable and don't cached the result. use unless will prevent the method invoke. Is this correct?
#Tonney Bing
First of all, my apologies for misguiding you on my previous answer...
If condition evaluates to false, then the method will always be
executed and the result subsequently cached.
The last part is NOT true. In fact, the condition attribute does prevent the #Cacheable method result from being cached. But, neither the condition nor the unless attribute prevent the #Cacheable service method from being invoked.
Also, my code example above was not correct. The unless attribute needs to be set to true to prevent caching of the #Cacheable method result.
After re-reading this section in the Spring Reference Guide, I came to realize my mistake and wrote an example test class to verify Spring's "conditional" caching behavior.
So...
With respect to your business use case, the way I understand it based on your original question and subsequently, your response to my previous answer, you have a #Cacheable service method that needs to be suppressed of invocation in the read-only app regardless of whether the value is in the cache or not! In other words, the value should always be retrieved from the cache and the #Cacheable service method should NOT be invoked in read-only mode.
Now to avoid polluting your application code with Spring infrastructure component references, and specifically, with a Spring CacheManager, this is a good example of a "cross-cutting concern" (since multiple, mutating-based application service operations may exist) and therefore, can be handled appropriately using AOP.
I have coded such an example satisfying your requirements here.
This is a self-contained test class. The key characteristics of this test class include...
The use of external configuration (by way of the app.mode.read-only System property) to determine if the app is in read-only mode.
The use of AOP and a custom Aspect to control whether the subsequent invocation of the Joint Point (i.e. the #Cacheable service method) is allowed (no, in a read-only context). In addition, I appropriately set the order in which the Advice (namely, the #Cacheable based advice along with the handleReadOnlyMode advice in the UseCacheExclusivelyInReadOnlyModeAspect Aspect) should fire based on precedence.
Take note of the #Cacheable annotation on the service method...
#Cacheable(value = "Factorials", unless = "T(java.lang.System).getProperty('app.mode.read-only', 'false')")
public Long factorial(long number) { .. }
You can see the intended behavior with the System.err output statements in the test class.
Hope this helps!