Spock does not detect method invocation - unit-testing

Spock does not detect doTip method invocation
(I need shared for some "where" blocks.)
Used latest groovy and spock.
Why this code is wrong?
How fix it?
import spock.lang.Shared
import spock.lang.Specification
class Test extends Specification {
def controller
#Shared
String g = ""
#Shared
def tip = Mock(Tip)
def "test"() {
controller = new TController(tip: tip)
when:
controller.transform(g)
then:
1 * tip.doTip(_)
}
}
class Tip {
def doTip(String f) {}
}
class TController {
Tip tip
def transform(String g) {
tip.doTip(g)
}
}

Use setup() to create the mock as shown below:
#Grab(group='org.spockframework', module='spock-core', version='1.0-groovy-2.4')
import spock.lang.*
class Test extends Specification {
def controller
#Shared String g = ""
#Shared tip
def setup() {
tip = Mock(Tip)
}
def "test"() {
given:
controller = new TController(tip: tip)
when:
controller.transform(g)
then:
1 * tip.doTip(_)
}
}
class Tip {
def doTip(String f) {}
}
class TController {
Tip tip
def transform(String g) {
tip.doTip(g)
}
}
Result
JUnit 4 Runner, Tests: 1, Failures: 0, Time: 78

Related

Grails Test mockFor java.util.Calendar.getInstance()

I am trying to mock a Calendar on grails 2.2.2 unit test using grails.test.mixin
.mockFor but I have the following error:
No more calls to 'getInstance' expected at this point. End of demands.
Does anyone know if this is possible to mock Calendar?
The test class:
#TestFor(FechaService)
class FechaServiceTests {
void testGetMesesCrearMetrica() {
given:
def cal = Calendar.getInstance().set(Calendar.MONTH, 0)
def mockCalendar = mockFor(Calendar)
mockCalendar.demand.static.getInstance{-> cal}
mockCalendar.createMock()
when:
def meses = service.getMesesCrearMetrica()
...
}
}
The service method:
def getMesesCrearMetrica(){
def meses = [:]
for(def mes : Meses.values()){
if(mes.value -1 == Calendar.getInstance().get(Calendar.MONTH)) break
meses[mes.value] = mes.name()
}
return meses
}
You could change the signature of the method under test so that it accepts a Calendar as an argument.
Failing that, I would also try using metaClass.
#ConfineMetaClassChanges(Calendar)
void testGetMesesCrearMetrica() {
given:
def cal = Calendar.getInstance()
cal.set(Calendar.MONTH, 0)
Calendar.metaClass.static.getInstance = { cal }
when:
def meses = service.getMesesCrearMetrica()
...
}

Using mockFor to mock Sql.call() in a groovy unit test

I'm trying to mock newInstance() and call() in groovy.sql.Sql:
package com.sample
import grails.test.GrailsUnitTestCase
import groovy.mock.interceptor.MockFor
import groovy.sql.Sql
class MySampleTests extends GrailsUnitTestCase {
void testThat_SqlCall_IsInvokedWithexpectedQuery() {
def mockSql = new MockFor(Sql.class)
mockSql.demand.newInstance { def datasource->
return mockSql
}
mockSql.demand.call { def sql ->
return 0
}
mockSql.use {
MySample targetObject = new MySample()
targetObject.myMethod()
}
}
}
Where this is the target code:
package com.sample
import groovy.sql.Sql
class MySample {
def dataSource
def myMethod() {
def conn = Sql.newInstance(dataSource)
conn.call("test")
}
}
It errs out with:
groovy.lang.MissingMethodException: No signature of method: groovy.mock.interceptor.MockFor.call() is applicable for argument types: (java.lang.String) values: [test]
The error makes it seem like the call() method is not being mocked. Is that the case? What's a fix for it?
Replacing mockSql.demand.call with mockSql.metaClass.call provides a mocked method, but requires manual verification that the method is called, and of the parameter values:
package com.sample
import grails.test.GrailsUnitTestCase
import groovy.mock.interceptor.MockFor
import groovy.sql.Sql
class MySampleTests extends GrailsUnitTestCase {
void testThat_SqlCall_IsInvokedWithexpectedQuery() {
def mockSql = new MockFor(Sql.class)
def callInvoked = 0
mockSql.demand.newInstance { def datasource->
return mockSql
}
mockSql.metaClass.call { def sql ->
assert sql == "test"
++callInvoked
return 0
}
mockSql.use {
MySample targetObject = new MySample()
targetObject.myMethod()
}
assert callInvoked == 1
}
}
I don't know enough groovy yet to understand why this is the case, but it solved the issue for me.
Additional cosmetic changes plus moving the targetObject instantiation out of mySql.use {} result in:
package com.sample
import grails.test.GrailsUnitTestCase
import groovy.mock.interceptor.MockFor
import groovy.sql.Sql
class MySampleTests extends GrailsUnitTestCase {
MySample targetObject = new MySample()
void testThat_SqlCall_IsInvokedWithexpectedQuery() {
def mockSql = new MockFor(Sql)
def callInvoked = 0
mockSql.demand.newInstance { datasource->
mockSql
}
mockSql.metaClass.call { sql ->
assert sql == "test"
++callInvoked
0
}
mockSql.use {
targetObject.myMethod()
}
assert callInvoked == 1
}
}

Unit testing session variable in controller with spock

I am trying to test that a session variable is set up in a method in a controller using a unit test in a Grails controller but it is complaining about setting a readonly property:
Cannot set readonly property: session for class: MyController
I have something like this:
class MyController {
def settingSession = {
session.var1 = "hello world!"
}
}
and this would be my test:
class MyControllerUnitTest extends ControllerSpec {
def "My test with sessions"() {
when:
controller.settingSession()
then:
controller.session.var1 == "hello world!"
}
}
I guest that probably I should write an integration test but I would like to know if there is any possibility of doing this in a unit test.
The following test will pass with Grails 2.1.0
A controller:
// grails-app/controllers/demo/MyController.groovy
package demo
class MyController {
def settingSession() {
session.band = 'King Crimson'
}
}
A unit test:
// test/unit/demo/MyControllerTests.groovy
package demo
import grails.test.mixin.*
import org.junit.*
#TestFor(MyController)
class MyControllerTests {
void testSettingSession() {
controller.settingSession()
assert session.band == 'King Crimson'
}
}
If you are using Spock:
// test/unit/demo/MyControllerSpec.groovy
package demo
import grails.test.mixin.*
import spock.lang.Specification
#TestFor(MyController)
class MyControllerSpec extends Specification {
void 'test session'() {
when:
controller.settingSession()
then:
session.band == 'King Crimson'
}
}

How to write unit test for this controller method?

I trying to learn grails unit testing, I having a method like
def getProductList(){
List<Product> products = productService.getSodaProductList();
render(view:"productList",model:[products:products])
}
I want to write test function to this using GrailsUnitTestCase
I tried like this
void testGetSodaProductList(){
def sodaProduct = new SodaProduct(productName:"Test Product",productDesc: "",price:10.0);
mockDomain(SodaProduct,[sodaProduct])
def controller = new SodaProductController();
mockController(controller)
def list = controller.getSodaProductList();
assertEquals(2,list.model.products.size())
}
But not working, can some suggest how to write this test function?
I generally use the following way for unit testing
Using spock:
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(SodaProductController)
#Mock([SodaProduct, ProductService])
class SodaProductControllerSpec extends Specification {
void testGetSodaProductList() {
when:
SodaProduct sodaProduct =
new SodaProduct(productName: "Test Product",
productDesc: "Desc", price: 10.0)
controller.getProductList()
then:
view == "/sodaProduct/productList"
model.products.size() == 2
}
}
Without spock:
import grails.test.mixin.Mock
import grails.test.mixin.TestFor
#TestFor(SodaProductController)
#Mock([SodaProduct, ProductService])
class SodaProductControllerTests {
void testGetSodaProductList() {
SodaProduct sodaProduct =
new SodaProduct(productName: "Test Product",
productDesc: "Desc", price: 10.0)
controller.getProductList()
assert view == "/sodaProduct/productList"
assert model.products.size() == 2
}
}

How to mock a service in grails TagLib unit test

I have TagLib, Service and TestCase as follows
How to mock a service in a taglib to get expected result from service
TagLib:
class SampleTagLib {
static namespace = "sample"
def baseService
def writeName = { attrs, body ->
def result = baseService.findAttributeValue(attrs.something)
if(result)
out << body()
}
}
Service:
class BaseService {
def findAttributeValue(arg1) {
return false
}
}
TagLibUnitTestCase:
import spock.lang.*
import grails.plugin.spock.*
import org.junit.*
import grails.test.mixin.*
import grails.test.mixin.support.*
import grails.test.mixin.Mock
#TestFor(SampleTagLib)
#Mock(BaseService)
class SampleTagLibSpec extends Specification {
def template
def setup(){
tagLib.baseService = Mock(BaseService)
}
def 'writeName'(){
given:
tagLib.baseService.findAttributeValue(_) >> true
def template ='<sample:writeName something='value'>output</sample:writeName>'
when: 'we render the template'
def output = applyTemplate(template, [sonething:'value')
then: 'output'
output =="output"
}
}
But it getting Error condition not satisfied. Getting output = " "
Expected output = "output"
You need to use the grails mockFor to mock out the service.
See Mocking Collaborators
Untested Example:
def strictControl = mockFor(BaseService)
strictControl.demand.findAttributeValue(1..1) { arg1 -> return true }
taglib.baseService = strictControl.createMock()