I have a few tests that are very similar in my Grails integration test suite (which uses Spock). I want to have a base test class which has the 90% of the common logic of the tests and then let test classes extend from it.
I was thinking:
public abstract BaseSpecification extends IntegrationSpec {
public baseTest() {
//
setUp:
//
...
when:
//
...
then:
...
}
}
and then:
public class SpecificTestSpecification extends BaseSpecification {
public baseTest() {
setup:
// more set up
super.baseTest();
when:
// some more specific testing
then:
// som more testing
}
}
But trying this I get two issues:
It runs both BaseClass and SpecificationClass
When the SpecificationClass runs, it fails on:
groovy.lang.MissingMethodException: No signature of method: BaseSpecification.baseTest() is applicable for argument types: () values: []
Possible solutions: any(), old(java.lang.Object), any(groovy.lang.Closure), notify(), wait(), Spy()
at
Any ideas how I can achieve inheritance in my spock integration tests?
I don't know if it can be done with Spock. When I tried I couln't find a way to reuse spock statements and what I did was to write a BaseSpecification class with utility methods that can be used inside spock statements.
This is an example test.
#TestFor(Address)
class AddressSpec extends BaseSpecification {
...
void "Country code should be 3 chars length"(){
when:
domain.countryCode = countryCode
then:
validateField('countryCode', isValid, 'minSize.notmet')
where:
[countryCode, isValid] << getMinSizeParams(3)
}
And the BaseSpecification class
class BaseSpecification extends Specification {
// Return params that can be asigned in `where` statement
def getMinSizeParams(Integer size){[
[RandomStringUtils.randomAlphabetic(size - 1), false],
[RandomStringUtils.randomAlphabetic(size), true]
]}
// Make an assetion, so it can be used inside `then` statement
protected void validateField(String field, String code, Boolean shouldBeValid){
domain.validate([field])
if(shouldBeValid)
assert domain.errors[field]?.code != code
else
assert domain.errors[field]?.code == code
}
}
It's an unit test but I think it should work with Integration tests too.
Okay, now I got your point.
You can pretty much use like this:
class BaseSpecification extends IntegrationSpec {
//User userInstance
def setup() {
// do your common stuff here like initialize a common user which is used everywhere
}
def cleanup() {
}
}
class SpecificTestSpecification extends BaseSpecification {
def setup() {
// specific setup here. Will call the super setup automatically
}
def cleanup() {
}
void "test something now"() {
// You can use that userInstance from super class here if defined.
}
}
Related
I have a very simple class as shown
class MyClass {
public static String getName(String input)
{
return toUpperCase(input);
}
public static String toUpperCase(String name)
{
return name.toUpperCase();
}
}
To test the above I have written a Test Case using Spock FW as shown below:
class MyClassTest extends Specification{
def 'check uppercase scnario'() {
given:
MyClass myClass = new MyClass();
when:
myClass.getName("test")
then: ""
1*myClass.toUpperCase("test");
}
}
But when I run this I see 0 Interactions
You cannot verify interactions on static Java methods. Just make your methods non-static. Besides, in the given: block, you are instantiating the class, so I guess you want to use instance methods anyway.
class MyClass {
public String getName(String input) {
return toUpperCase(input);
}
public String toUpperCase(String name) {
return name.toUpperCase();
}
}
Furthermore, if you wish to verify interactions on self-invocation calls, a Mock() is not what you need. Instead, simply use a Spy():
class MyClassTest extends Specification {
def 'check uppercase scnario'() {
given:
MyClass myClass = Spy()
when:
myClass.getName("test")
then:
1 * myClass.toUpperCase("test");
}
}
Try it in the Groovy Web Console.
Using Grails 3.2.8 and the Spock framework for testing, given the following controller class:
class SomeController {
def doSomething() {
// do a few things, then:
someOtherMethod()
}
protected void someOtherMethod() {
// do something here, but I don't care
}
}
How can I test the doSomething() method to make sure someOtherMethod() is called exactly once?
This is my attempt that failed:
#TestFor(SomeController)
class SomeControllerSpec extends Specification {
void "Test that someOtherMethod() is called once inside doSomething()"() {
when:
controller.doSomething()
then:
1 * controller.someOtherMethod(_)
}
}
Error message:
Too few invocations for:
1 * controller.someOtherMethod(_) (0 invocations)
Note: Imports have been omitted to focus on the problem at hand
You can't do that as controller is not a mocked object. Instead, you need to use metaclass like this:
#TestFor(SomeController)
class SomeControllerSpec extends Specification {
void "Test that someOtherMethod() is called once inside doSomething()"() {
given:
Integer callsToSomeOtherMethod = 0
controller.metaClass.someOtherMethod = {
callsToSomeOtherMethod++
}
when:
controller.doSomething()
then:
callsToSomeOtherMethod == 1
}
}
I would like to mock a service method in an integration test for one test, however I don't know how to get a reference to the service as it's added to the controller via dependency injection. To further complicate things the service is in a webflow, but I know it's not stored in the flow as the service is not serialized.
Ideal mocking scenario:
Get reference to the service
Mock the method via the metaClass
Main test
Set the metaClass to null so it's replaced with the original
Methods like mockFor so far don't seem to effect the service.
Example of the setup:
Controller:
package is.webflow.bad
import is.webflow.bad.service.FakeService
class FakeController
{
def index = {
redirect(action: 'fake')
}
def fakeFlow = {
start {
action {
flow.result = fakeService.fakeCall()
test()
}
on('test').to('study')
}
study {
on('done').to('done')
}
done {
System.out.println('done')
}
}
}
Service:
package is.webflow.bad.service
class FakeService
{
def fakeCall()
{
return 'failure'
}
}
Test:
package is.webflow.bad
import static org.junit.Assert.*
import grails.test.WebFlowTestCase
import is.webflow.bad.service.FakeService
import org.junit.*
class FakeControllerFlowIntegrationTests extends WebFlowTestCase
{
def controller = new FakeController()
def getFlow() { controller.fakeFlow }
String getFlowId() { "fake" }
#Before
void setUp() {
// Setup logic here
super.setUp()
}
#Test
void testBasic()
{
startFlow()
assertCurrentStateEquals 'study'
assertEquals 'failure', getFlowScope().result
}
#Test
void testServiceMetaClassChange()
{
// want to modify the metaClass here to return success
startFlow()
assertCurrentStateEquals 'study'
assertEquals 'success', getFlowScope().result
}
}
You can inject the service into your Integration test using "#AutoWired" or using application context you get reference. Am i missing something?
#Autowired
private YourService yourservice;
or
#Autowired
private ApplicationContext appContext;
YourService yourService = (YourService)appContext.getBean("yourService");
Here you go:
void "test something"() {
given: "Mocked service"
someController.someInjectedService = [someMethod: { args ->
// Mocked code
return "some data"
] as SomeService
when: "Controller code is tested"
// test condition
then: "mocked service method will be called"
// assert
}
So, I am trying to test the following Grails service implementation:
class BookService {
def searchBooks(String search) {
if (!search) {
return []
}
Book.searchBooks(search)
}
}
It uses a method defined in the Book domain class:
class Book {
String title
static def searchBooks(String search) {
Book.findByTitleLike(search)
}
}
So, this is the test code I've been trying:
#TestFor(BookService)
#Mock(Book)
class BookServiceSpec extends Specification {
void "should search books"() {
setup:
new Book(title: 'The Stand').save()
new Book(title: 'Under the Dome').save()
new Book(title: 'Bag of Bones').save()
when:
service.searchBooks('ones')
then:
1 * Book.searchBooks()
}
}
But, it always fails with:
Too few invocations for:
1 * Book.searchBooks() (0 invocations)
I've debugged the code running in an IDE and the method seems to be indeed executed, but Spock does not register the execution.
What am I missing?
Is there something else I have to do to mock the domain class method?
Here is a sample project with the code.
I'm using Grails 1.3.7. I'm trying to test a redirect in my integration test. Here is my controller and method in question ...
class HomeController {
def design = {
....
if (params.page) {
redirect(uri: "/#/design/${params.page}")
}
else {
redirect(uri: "/#/design")
}
break;
}
}
However in my integration test, the call to "controller.response.redirectedUrl" is failing (always returns null) even though I know the redirect call is being made (verified through logging). What is wrong with the integration test below?
class HomeControllerTests extends grails.test.ControllerUnitTestCase {
....
void testHomePageDesign() {
def controller = new HomeController()
// Call action without any parameters
controller.design()
assert controller.response.redirectedUrl != null
assertTrue( responseStr != "" )
}
Thanks, - Dave
Changing your HomeControllerTests to extend GrailsUnitTestCase should fix the problem.
class HomeControllerTests extends grails.test.GrailsUnitTestCase {
....
}
The various ways of generating a test class all seem to vary the class that is extended.
create-integration-test => GroovyTestCase
create-unit-test => GrailsUnitTestCase
create-controller => ControllerUnitTestCase
However, according to the Test section of the Grails User Guide, GrailsUnitTestCase is the core part of the testing frame and, at least in 1.3.7, that is the best class to base test classes on.