Override Features in extended Specs - spock

I'm attempting to setup a testing scenario where I can publish a JAR of tests that will run the same sets of tests 95% of the time but there will be 5% of the tests that need to either override or stop a feature in the parent class. Is it possible to override parent specifications?
class ParentSpec extends Specification {
def "goto home page"() {
given:
to NormalHomePage
expect:
at NormalHomePage
}
}
... in a separate project that brings in the dependency for the ParentSpec
class ChildSpec extends ParentSpec {
#Override
def "goto home page"() {
given:
to SpecificHomePage
expect:
at SpecificHomePage
}
}
Is there something that I can do to either do this or simulate this?

Overriding feature methods isn't currently supported. With some effort, it would be possible to write an extension that skips the "super" method.

Related

Add custom information to Spock Global Extension

I have configured Spock Global Extension and static class ErrorListener inside it. Works fine for test errors when I want to catch feature title and errors if they happen. But how can I add some custom information to the listener?
For example I have test that calls some API. In case it fails I want to add request/response body to the listener (and report it later). Obviously I have request/response inside the feature or I can get it. How can I pass this information to the Listener and read later in the handling code?
package org.example
import groovy.json.JsonSlurper
import org.spockframework.runtime.AbstractRunListener
import org.spockframework.runtime.extension.AbstractGlobalExtension
import org.spockframework.runtime.model.ErrorInfo
import org.spockframework.runtime.model.IterationInfo
import org.spockframework.runtime.model.SpecInfo
import spock.lang.Specification
class OpenBrewerySpec extends Specification{
def getBreweryTest(){
def breweryText = new URL('https://api.openbrewerydb.org/breweries/1').text
def breweryJson = new JsonSlurper().parseText(breweryText)
//TODO catch breweryText for test result reporting if it is possible
expect:
breweryJson.country == 'United States'
}
def cleanup() {
specificationContext.currentSpec.listeners
.findAll { it instanceof TestResultExtension.ErrorListener }
.each {
def errorInfo = (it as TestResultExtension.ErrorListener).errorInfo
if (errorInfo)
println "Test failure in feature '${specificationContext.currentIteration.name}', " +
"exception class ${errorInfo.exception.class.simpleName}"
else
println "Test passed in feature '${specificationContext.currentIteration.name}'"
}
}
}
class TestResultExtension extends AbstractGlobalExtension {
#Override
void visitSpec(SpecInfo spec) {
spec.addListener(new ErrorListener())
}
static class ErrorListener extends AbstractRunListener {
ErrorInfo errorInfo
#Override
void beforeIteration(IterationInfo iteration) {
errorInfo = null
}
#Override
void error(ErrorInfo error) {
errorInfo = error
}
}
}
Create file src/test/resources/META-INF/services/org.spockframework.runtime.extension.IGlobalExtension
and place string "org.example.TestResultExtension" there to enable extension.
I am pretty sure you found my solution here. Then you also know that it is designed to know in a cleanup() methods if the test succeeded or failed because otherwise Spock does not make the information available. I do not understand why deliberately omitted that information and posted a fragment instead of the whole method or at least mentioned where your code snippet gets executed. That is not a helpful way of asking a question. Nobody would know except for me because I am the author of this global extension.
So now after having established that you are inside a cleanup() method, I can tell you: The information does not belong into the global extension because in the cleanup() method you have access to information from the test such as fields. Why don't you design your test in such a way that whatever information cleanup() needs it stored in a field as you would normally do without using any global extensions? The latter is only meant to help you establish the error status (passed vs. failed) as such.
BTW, I even doubt if you need additional information in the cleanup() method at all because its purpose it cleaning up, not reporting or logging anything. For that Spock has a reporting system which you can also write extensions for.
Sorry for not being more specific in my answer, but your question is equally unspecific. It is an instance of the XY problem, explaining how you think you should do something instead of explaining what you want to achieve. Your sample code omits important details, e.g. the core test code as such.

Programmatically skip a test in Spock

How do I programmatically skip a test in the Spock framework? I know I can annotate a test with #Ignore to skip it, or use #IgnoreIf to skip tests based on environmental variables and the like. But is there a way to run arbitrary code that decides whether or not a test should run?
For example, let's say I have an integration test that has to connect to a third-party service's sandbox environment. Outages in the service's sandbox environment cause the test to fail. Assuming I've written a method canConnectToService that checks if the test will be able to connect to this service, how do I write a test that will be skipped if canConnectToService() returns false?
Use JUnit's Assume class. Specifically, you could write Assume.assumeTrue(canConnectToService()) at the beginning of your test to skip the test if the third party service is unavailable. This method will throw an AssumptionViolatedException if canConnectToService() returns false, and Spock ignores tests that are interrupted by an AssumptionViolatedException for JUnit compatibility (see this bug report).
There is another alternative (maybe it didn't exists before):
Using instance inside #Requires or #IgnoreIf:
Examples using inheritance, but not required:
abstract class BaseTest extends Specification {
abstract boolean serviceIsOnline()
#Requires({ instance.serviceIsOnline() })
def "some test" () { .. }
}
SubSpecification:
class OnlineTest extends BaseTest {
boolean serviceIsOnline() {
// Test connection, etc.
return true
}
}
class SkipTest extends BaseTest {
boolean serviceIsOnline() {
return false
}
}
Documentation
instance
The specification instance, if instance fields, shared
fields, or instance methods are needed. If this property is used, the
whole annotated element cannot be skipped up-front without executing
fixtures, data providers and similar. Instead, the whole workflow is
followed up to the feature method invocation, where then the closure
is checked, and it is decided whether to abort the specific iteration
or not.
As an extra, another way you can programmatically skip a test is using the where label:
class MyTest extends Specification {
List getAvailableServices() {
// You can test connections here or your conditions
// to enable testing or not.
return available
}
#Unroll
def "Testing something"() {
setup:
URL url = serviceUrl.toURL()
expect:
assert url.text.contains("Hello")
where:
serviceUrl << availableServices
}
}

How to test logic in constructor?

My test class like this:
public class HandlerTest extends Specification {
Handler hander
EventBus eventBus=Mock()
def setup(){
handler=new Handler(eventBus)
}
def "constructor"(){
//How to verify two events do get added to eventBus?
}
}
and Constructor of Handler(it is a java class)
public Handler(EventBus eventBus)
{
eventBus.add(FetchSearchWordsEvent.TYPE, this);
eventBus.add(SetSearchBoxTextEvent.TYPE, this);
}
Question is:
how to verify that two events do get registered?
I would move the call to Handler constructor into the test itself given that it is the function under test.
Try the following:
public class HandlerTest extends Specification {
Handler hander
def mockEventBus = Mock(EventBus)
def "constructor"(){
when:
new Handler(mockEventBus)
then:
1 * mockEventBus.add(FetchSearchWordsEvent.TYPE, _ as Handler)
1 * mockEventBus.add(SetSearchBoxTextEvent.TYPE, _ as Handler)
}
}
The functionality of EventBus.add() should be tested separately.
It depends on how registerHandler is implemented, and what exactly you want to verify. If the goal is to verify that the constructor ultimately calls some methods on eventBus, you can just use regular mocking. If the goal is to verify that the constructor calls registerHandler on itself, you can use partial mocking using Spy(), as explained in the Spock reference documentation.
PS: Note that partial mocking is considered a smell. Often it's better to change the class under test to make it easier to test. For example, you could add a method that allows to query which handlers have been registered. Then you won't need mocking at all.

How to test a controller that has a #Mixin of a Basecontroller

I've created a BaseController that I mixinto other Controllers.
Example:
class BaseController () {
def somemethod () {
return "some method"
}
}
#Mixin(BaseController)
class MyController {
def getsomething() {
def test = somemethod()
return test
}
}
I'm trying to write a test case for MyController however, it fails because it can't find somemethod.
My test currently looks like this
#TestFor(MyController)
class MyControllerSpec extends Specification {
def "test getsomething" () {
when:
def m = controller.getsomething()
then:
response.contentAsString == "some method"
}
}
But I keep getting errors like these:
No signature of method: somemethod() is applicable for argument types: () values: []
Question
How can I write spock test for MyController so that it finds somemethod as well
Does using #TestMixin(BaseController) in the Spock test for MyController work?
Ans:- No, it is not required.
UPDATE
There is a small modification required in MyController. Use render instead of return. Here is the detail:
class BaseController {
def someMethod() {
"Some Method"
}
}
import grails.util.Mixin
//Remember to use Grails #Mixin instead of Groovy #Mixin
#Mixin(BaseController)
class MyController {
def getSomething() {
def test = someMethod()
render test
}
}
//Unit Test
#TestFor(MyController)
class MyControllerUnitSpec extends Specification {
void "test get something"() {
when:
controller.getSomething()
then:
response.contentAsString == "Some Method"
}
}
//Controller Integration Test
import grails.plugin.spock.ControllerSpec
class MyControllerIntSpec extends ControllerSpec {
void "test get something integration"() {
when:
controller.getSomething()
then:
controller.response.contentAsString == "Some Method"
}
}
Notes:-
I found some difficulties while testing which are listed below:-
The above tests passed with an initial run. But, when I changed render to return just to see my tests failing, I got compilation errors because of the Grails #Mixin I used in MyController (two version of withFormat). Sometimes I think it does not play well. Changing the mixin to Groovy #Mixin everything went good. I did not like that. I had to stick to Grails #Mixin. Apparently and surprisingly, doing a grails clean && grails compile eradicated the issue. I was able to use Grails #Mixin properly. I am still looking at this discrepancy.
If the above problem were persistent, I would have thought of adding runtime mixin in the setup() method in unit test.
Like
def setup(){
//I would not like to do the same in Integration test
//Integration test should do it for me atleast.
MyController.mixin BaseController
}
I used ControllerSpec instead of IntegrationSpec in integration test. Seems like injection and convention is maintained better in ControllerSpec for controllers. If you see, nowhere am I instantiating MyContoller in the int test.
I have not tested it in normal Junit's Unit and Integration tests, they should be good as well.
My strong advice is to not use mixins in Grails at all. It generates faulty bahvior in tests. Also you need an extra code to apply these mixins for tests, which is bad.
For further information read this replay: http://grails.1312388.n4.nabble.com/grails-2-2-2-upgrade-from-2-2-0-breaks-mixin-on-controller-tp4645461p4645466.html, which applies to mixins in Grails in general, or take look of many issues reported in comments of this issue: http://jira.grails.org/browse/GRAILS-8652 (classes lose their mixins during unit tests).
Based on the answers in this thread, http://grails.1312388.n4.nabble.com/Testing-a-controller-that-has-a-Mixin-td4645595.html
I ended up using,
void setup() {
MyController.mixin(BaseController)
}

Grails - save() failing with MissingMethodExcepition in integration test

I'm learning groovy / grails, and writing my first integration test.
It's currently failing with:
groovy.lang.MissingMethodException: No
signature of method:
com.mangofactory.scurry.User.save() is
applicable for argument types: ()
values: []
My test isn't doing anything fancy:
class UserEventControllerTests extends ControllerUnitTestCase {
protected void setUp() {
super.setUp()
}
protected void tearDown() {
super.tearDown()
}
void testAddingAUser()
{
def user = new User(emailAddress: "martypitt#test.com")
user.save()
}
}
Saving the entity works fine when I do it through the scaffolded pages provided by grails.
What have I missed?
If you want it to be an integration tests it shouldn't extend one of the unit test base classes, so change it to
class UserEventControllerTests extends GroovyTestCase {
...
}
and make sure it's in test/integration, not test/unit.
But it looks like you want to test a controller (it's called UserEventControllerTests) which should extend ControllerUnitTestCase. If that's the case then you should be doing unit tests, but mocking the domain layer (using mockDomain and others) since you want to focus on controller logic, not persistence. Test domain classes in proper integration tests using a database.
This is all described in chapter 10 of the docs: http://grails.org/doc/latest/

Resources