I have two totally independent tests verifying two different builders (simplified as much as possible). The second one is failing, but there is no reason for that. Why is it happening?
def "first"() {
StringBuilder builder
expect: true
}
def "second"() {
expect: true
where:
builder << [new ProcessBuilder()]
}
org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot
cast object 'java.lang.ProcessBuilder#186f8716' with class
'java.lang.ProcessBuilder' to class 'java.lang.StringBuilder'
This question is actually a duplicate of that one.
Bottom line: You have hit bug #880 in Spock which has been resolved about a week ago and the fix of which you can probably enjoy in the final version Spock 2.0 or in the next milestone release if there is one more before the final one.
Workaround: rename the second variable to something else.
Technical background about this problem and related ones fixed at the same time can be found in the corresponding pull request #1111.
Related
Im using Spock for my tests and I have multiple classes to test. I want to tell Spock to test each class in specific order. Is there a way to do this? I noticed TestNG has got #AfterTest annotation, so does Spock have something similar?
You can't specify Spock test classes execution order. However Spock allows you to specify methods execution order when you add #Stepwise annotation to your test class - in this case Spock will execute all methods in order from top to bottom and if one method fails it will ignore remaining methods in this test class.
Indicates that a spec's feature methods should be run sequentially in their declared order (even in the presence of a parallel spec runner), always starting from the first method. If a method fails, the remaining methods will be skipped. Feature methods declared in super- and subspecs are not affected.
#Stepwise is useful for specs with (logical) dependencies between methods. In particular, it helps to avoid consecutive errors after a method has failed, which makes it easier to understand what really went wrong.
Reference: http://spockframework.org/spock/javadoc/1.1/spock/lang/Stepwise.html
#Stepwise
class StepwiseExample extends Specification {
def "first test method to run"() {
// ....
}
def "second test method to run"() {
// ....
}
def "if previous method failed this one will be ignored"() {
// ....
}
}
Using org.junit.runners.Suite
Jeff Scott Brown gave a good comment about JUnit's #Suite.SuiteClasses. In this case you create a class where you can aggregate your test classes (specifications) into a single test suite and those classes will be executed in the order they have been defined in the suite. Consider following example:
import org.junit.runner.RunWith
import org.junit.runners.Suite
#RunWith(Suite)
#Suite.SuiteClasses([
Test2Specification,
Test1Specification
])
class TestSuiteSpecification { }
This suite executes two specifications Test2Specification and Test1Specification in the defined order:
I've seen a bunch of questions related to this subject, but none of them offers anything that would be an acceptable solution (please, no loading external Groovy scripts, no calling to sh step etc.)
The operation I need to perform is a oneliner, but pipeline limitations made it impossible to write anything useful in that unter-language...
So, here's minimal example:
#NonCPS
def encodeProperties(Map properties) {
properties.collect { k, v -> "$k=$v" }.join('|')
}
node('dockerized') {
stage('Whatever') {
properties = [foo: 123, bar: "foo"]
echo encodeProperties(properties)
}
}
Depending on whether I add or remove #NonCPS annotation, or type declaration of the argument, the error changes, but it never gives any reason for what happened. It's basically random noise, that contradicts the reality of the situation (at times it would claim that some irrelevant object doesn't have a method encodeProperties, other times it would say that it cannot find a method encodeProperties with a signature that nobody was trying to call it with (like two arguments instead of one) and so on.
From reading the documentation, which is of disastrous quality, I sort of understood that maybe functions in general aren't serializable, and that is why you need to explain this explicitly to the Groovy interpreter... I'm sorry, this makes no sense, but this is roughly what documentation says.
Obviously, trying to use collect inside stage creates a load of new errors... Which are, at least understandable in that the author confesses that their version of Groovy doesn't implement most of the Groovy standard...
It's just a typo. You defined encodeProperties but called encodeProprties.
#Stepwise
Class TestCaseOne extends Specification{
def test(){
expect:
assert something
}
def testValidation(){
expect:
assert something
}
def test(){}
expect:
assert something
}
def testValidation(){
expect:
assert something
}
}
I want testing should stop if test method fails but it should continue if testValidation method fails. Please let me know if it is possible.
I am using Groovy and spock.Thanks in advance.
According to this 'issue' which covers your question https://github.com/spockframework/spock/issues/456 recommended way if you want to achieve full test execution is to not use #Stepwise annotation.
robfletcher commented Aug 30, 2015
Just don't use #Stepwise then. Execution is sequential nevertheless. This might change
in case Spock itself ever gets some parallel execution support, but for now you'll be fine.
Reported by pniederw on 2013-10-24 08:47:44
What you are asking is not possible.
Either you use #Stepwise and it stops at the first failure. Or your don't use #Stepwise and it runs everything.
There is no way to mark specific methods on what should happen.
Split your test into two where one has the annotation and the other does not.
I'm trying to modularize my test cases, so I'm running a shared test case (as a procedure) that does something useful and returns a result value. As I need to pass-in non-string input properties, I have to run the test case from groovy:
def findLoopEndTC = testRunner.testCase.testSuite.testCases["TestCase - Find Loop End"]
assert findLoopEndTC != null, "Referred TC not found"
def runContext = new com.eviware.soapui.support.types.StringToObjectMap()
runContext.put("TestStepContext", context)
def runner = findLoopEndTC.run( runContext, false )
assert runner.status != com.eviware.soapui.model.testsuite.TestRunner.Status.FAILED : runner.reason
I've learned that the test case is run using the SINGLETON_AND_WAIT mode which ensures that the TestCase itself is run in a thread-safe way.
My question is how to return a value from the run test case in a thread-safe way?
I tried runner.getRunContext().getProperty("Result"), but it seems that the context properties are no longer there. So there seems to be only the "classical" way, findLoopEndTC.getPropertyValue("Result"), but this is aparently not thread-safe.
Are there other possibilities?
I use the free version of SoapUI.
I had the same problem. If I understand you correctly, this is what you want:
You’ve put the ‘calling’ context into a new context ‘runContext’:
context.get("TestStepContext").put("Results",resultList)
which has been passed in as the context for the test case to be run (synchronously). I’ll call the test case to be run ‘B’:
def runner = findLoopEndTC.run( runContext, false ) //in calling test case
To get something useful back from ‘B’, somewhere in it you need to put a value back into TestStepContext, e.g.:
context.get("TestStepContext").put("Results",resultList) //My results happened to be a list
In the calling test case, the line you need after the call to run the test case is:
def testResults = runContext.get("TestStepContext").get("Results")
Hope this makes sense.
I've been trying to work this out for the last few days too. I haven't been able to work out how to make it thread safe but I have an alternative approach which I think works pretty well.
I've based it on this http://forum.soapui.org/viewtopic.php?f=2&t=4681#p15731 suggestion from the SoapUI team. I found with the above solution it was still not thread safe, 99% of the time this worked but I found sometimes it's possible you can have two test cases both breaking out the loop at the same time.
To deal with this I set runningDeleteCar to the the hashcode for the current testRunner when it's broken out of the loop. I then double check this to make sure that some other test case hasn't gone in and changed it, if it doesn't match I just go back to the while loop. This stops the situation of two test cases breaking out at the same time.
This approach basically means only one test case can go through the shared test case at a time.
I'm new to spock and noticed the setup: step in a specification is scoped local to that specific test. How might I share setup across these fixtures similar to the traditional junit approach?
thank you!
def "setup with spock"() {
setup:
def message = new FooMessage()
def sut = new FooProcessor()
def builder = Mock(FooBuilder)
sut.setBuilder(builder)
when:
builder.buildFooUsing(_) >> {"bar"}
def result = sut.process(message)
then:
assert result == "bar"
}
You should use setupSpec() or look at #Shared annotation if you want to share a single object across tests
From Spock documentation
1.3.4 Sharing of Objects between Iterations
In order to share an object between iterations, it has to be kept in a #Shared or static field.
Note: Only #Shared and static variables can be accessed from within a
where: block.
Note that such objects will also be shared with other methods. There is currently no good way to share an object just
between iterations of the same method. If you consider this a problem, consider putting each method into a separate
spec, all of which can be kept in the same file. This achieves better isolation at the cost of some boilerplate code.