I am currently practicing test driven development in groovy using spock.
I have 1 set of tests where 3 different implementations doing the same thing: iterative, recursive, and memoized.
so I have created an abstract class to hold the tests, and then created 3 different files to return the concrete class implementation to run the tests. I have iterative and recursive working, but I am having issues with memoize()
import spock.lang.Specification
abstract class FibonacciTest extends Specification {
private calculator
abstract def getCalculator()
def setup() {
calculator = getCalculator()
}
def "test canary"() {
expect:
true
}
// more tests
}
class RecursiveFibonacciTest extends FibonacciTest {
def getCalculator() {
new RecursiveCalculator()
}
}
class IterativeFibonacciTest extends FibonacciTest {
def getCalculator() {
new IterativeCalculator()
}
}
class MemoizeFibonacciTest extends FibonacciTest {
def getCalculator() {
new MemoizeCalculator()
}
}
class RecursiveCalculator {
def getFibonacci(position) {
if (position < 2) {
1
}
else {
getFibonacci(position - 1) + getFibonacci(position - 2)
}
}
}
class IterativeCalculator {
def getFibonacci(position) {
if (position < 2) {
1
}
else {
def value = 1
def previousValue = 1
for (i in 2..position) {
def temporaryValue = previousValue
previousValue = value
value = temporaryValue + previousValue
}
value
}
}
}
So I've got the iterative and recursive working, but having problems getting the memoize to work.. I think it should work with this, but its not.. anyone know what I'm doing wrong?
class MemoizeCalculator {
def getFibonacci = { position ->
if (position < 2)
1
else
getFibonacci.call(position - 1) + getFibonacci.call(position - 2)
}.memoize()
}
You can't reference the getFibonacci variable from the same statement that declares it. Either change getFibonacci.call to call, or declare the variable (def getFibonacci) before assigning it (getFibonacci = ...).
Related
def withLocal(Closure cl) {
def credentialsId = env.CREDENTIALS_ID
if (credentialsId) {
echo("credentials Id=${credentialsId}")
} else {
throw new Exception("credentials not setup - env.CREDENTIALS_ID")
}
}
Excepting shouldFail and ShouldPass test cases for above groovy code.
Depending on the test-framework, the code might be slightly different, but I would put it like so:
class A {
def withLocal(Closure cl) {
def credentialsId = env.CREDENTIALS_ID
if (credentialsId) {
echo("credentials Id=${credentialsId}")
} else {
throw new Exception("credentials not setup - env.CREDENTIALS_ID")
}
}
}
// Test
// test 1 should pass: check if echo is called
// mock env with some value
A.metaClass.env = [ CREDENTIALS_ID:'abz123' ]
String out
// mock echo()
A.metaClass.echo = { out = it }
A a = new A()
a.withLocal{}
assert out == 'credentials Id=abz123'
// test 2 should fail: check if exception thrown
// mock env with empty map
A.metaClass.env = [:]
a = new A()
try{
a.withLocal{}
}catch( e ){
assert e.message == 'credentials not setup - env.CREDENTIALS_ID'
}
I have a controller like this:
class NotificationApiController {
def countService
def getCount() {
def results = countService.getCount()
render results as JSON
}
}
And the controller test like this:
Closure doWithSpring() {{ ->
countService(CountService)
}}
CountService countService
def setup() {
}
def cleanup() {
}
void "test getCount method"() {
given:
def countService = Mock(CountService) {
1 * getCount(_) >> [count: 2]
}
when:
def y = controller.getCount()
then:
y == [count: 2]
}
It appears it always calls into the actual CountService injected in Closure doWithSpring(), not my mock countService, but without the definition of Closure doWithSpring()..., I will get this error
Cannot invoke method getCount() on null object
java.lang.NullPointerException: Cannot invoke method getCount() on null object
The documentation on unit testing in 4.0 is really limited and I am not exactly sure how should I do this. I see some samples in Grails 2.3 or 3.3. version, but they all seems not working for me, mostly due to the difference of Spock and Mixin framework I guess. Any suggestions on how to do this?
You have omitted some details that might affect the recommendation but the project at https://github.com/jeffbrown/chrisjiunittest shows 1 way to go about this.
https://github.com/jeffbrown/chrisjiunittest/blob/a59a58e3b6ed6b47e1a8104f3e4d3bdb138abacc/src/test/groovy/chrisjiunittest/NotificationApiControllerSpec.groovy
package chrisjiunittest
import grails.testing.web.controllers.ControllerUnitTest
import spock.lang.Specification
class NotificationApiControllerSpec extends Specification implements ControllerUnitTest<NotificationApiController> {
void "test something"() {
setup:
// whether or not this is the right thing to do
// depends on some other factors, but this is
// an example of one approach...
controller.countService = Mock(CountService) {
getCount() >> [count: 2]
}
when:
controller.getCount()
then:
response.json == [count: 2]
}
}
Another option:
package chrisjiunittest
import grails.testing.web.controllers.ControllerUnitTest
import spock.lang.Specification
class NotificationApiControllerSpec extends Specification implements ControllerUnitTest<NotificationApiController> {
Closure doWithSpring() {
// whether or not this is the right thing to do
// depends on some other factors, but this is
// an example of one approach...
{ ->
countService MockCountService
}
}
void "test something"() {
when:
controller.getCount()
then:
response.json == [count: 2]
}
}
class MockCountService {
Map getCount() {
[count: 2]
}
}
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()
...
}
Given the following, how do I mock processMessage() using Spock, so that I can check that processBulkMessage() calls processMessage() n times, where n is the number of messages within a BulkMessage?
class BulkMessage {
List messages
}
class MyService {
def processBulkMessage(BulkMessage msg) {
msg.messages.each {subMsg->
processMessage(subMsg)
}
}
def processMessage(Message message) {
}
}
You can use spies and partial mocks (requires Spock 0.7 or newer).
After creating a spy, you can listen in on the conversation between the caller and the real object underlying the spy:
def subscriber = Spy(SubscriberImpl, constructorArgs: ["Fred"])
subscriber.receive(_) >> "ok"
Sometimes, it is desirable to both execute some code and delegate to the real method:
subscriber.receive(_) >> { String message -> callRealMethod(); message.size() > 3 ? "ok" : "fail" }
In my opinion this is not a well designed solution. Tests and design walk hand in hand - I recommend this talk to investigate it better. If there's a need to check if other method was invoked on an object being under test it seems it should be moved to other object with different responsibility.
Here's how I would do it. I know how visibility works in groovy so mind the comments.
#Grab('org.spockframework:spock-core:0.7-groovy-2.0')
#Grab('cglib:cglib-nodep:3.1')
import spock.lang.*
class MessageServiceSpec extends Specification {
def 'test'() {
given:
def service = new MessageService()
def sender = GroovyMock(MessageSender)
and:
service.sender = sender
when:
service.sendMessages(['1','2','3'])
then:
3 * sender.sendMessage(_)
}
}
class MessageSender { //package access - low level
def sendMessage(String message) {
//whatever
}
}
class MessageService {
MessageSender sender //package access - low level
def sendMessages(Iterable<String> messages) {
messages.each { m -> sender.sendMessage(m) }
}
}
It does not use Spock built-in Mocking API (not sure how to partially mock an object), but this should do the trick:
class FooSpec extends Specification {
void "Test message processing"() {
given: "A Bulk Message"
BulkMessage bulk = new BulkMessage(messages: ['a', 'b', 'c'])
when: "Service is called"
def processMessageCount = 0
MyService.metaClass.processMessage { message -> processMessageCount++ }
def service = new MyService()
service.processBulkMessage(bulk)
then: "Each message is processed separately"
processMessageCount == bulk.messages.size()
}
}
For Java Spring folks testing in Spock:
constructorArgs is the way to go, but use constructor injection. Spy() will not let you set autowired fields directly.
// **Java Spring**
class A {
private ARepository aRepository;
#Autowire
public A(aRepository aRepository){
this.aRepository = aRepository;
}
public String getOne(String id) {
tryStubMe(id) // STUBBED. WILL RETURN "XXX"
...
}
public String tryStubMe(String id) {
return aRepository.findOne(id)
}
public void tryStubVoid(String id) {
aRepository.findOne(id)
}
}
// **Groovy Spock**
class ATest extends Specification {
def 'lets stub that sucker' {
setup:
ARepository aRepository = Mock()
A a = Spy(A, constructorArgs: [aRepository])
when:
a.getOne()
then:
// Stub tryStubMe() on a spy
// Make it return "XXX"
// Verify it was called once
1 * a.tryStubMe("1") >> "XXX"
}
}
Spock - stubbing void method on Spy object
// **Groovy Spock**
class ATest extends Specification {
def 'lets stub that sucker' {
setup:
ARepository aRepository = Mock()
A a = Spy(A, constructorArgs: [aRepository]) {
1 * tryStubVoid(_) >> {}
}
when:
...
then:
...
}
}
I am updating unit tests in a Grails project. We were originally using version 1.3.9 and now we are updating to version 2.3.9. I am using Spock.
I keep getting this error:
results:
junit.framework.AssertionFailedError: Condition not satisfied:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
| | | |
| null false John
com.xxxxxx.xxxxx.FilterCategoryController#20574000
Here is the controller code:
#Secured(["hasAnyRole('CM_ADMIN')"])
def edit() {
def filterCategoryInstance = FilterCategory.get(params.id)
if (!filterCategoryInstance) {
flash.message = "${message(code: 'default.not.found.message', args: [message(code: 'dpFilterCategory.label', default: 'FilterCategory'), params.id])}"
redirect(action: "list")
}
else {
return [filterCategoryInstance: filterCategoryInstance]
}
}
and here is the test code:
#Mock([FilterCategory, FilterCategoryTag])
#TestFor(FilterCategoryController)
#TestMixin(DomainClassUnitTestMixin)
class FilterCategoryControllerSpec extends ExtendedControllerSpec {
def 'edit action: existing FilterCategory'() {
setup:
mockI18N(FilterCategoryController)
params.id = filterCategoryInstance.id
expect:
controller.edit() == [filterCategoryInstance: filterCategoryInstance]
where:
tag = new FilterCategoryTag(name: 'tag1')
filterCategoryInstance = new FilterCategory(name: "John",
submissionText:"John", sortOrder:0, 'filterCategoryTags': [tag])
}
And here is the ExtendedControllerSpec code. I hope I have included enough code:
I have looked at the following web pages for guidance:
#Mixin(MetaClassMixin)
class ExtendedControllerSpec extends Specification {
def props
protected void setup() {
//super.setup()
props = new Properties()
File file = new File("grails-app/i18n/messages.properties")
if (file.exists()) {
def stream = new FileInputStream(file)
props.load stream
stream.close()
}
mockI18N(controller)
}
def mockI18N = { controller ->
controller.metaClass.message = { Map map ->
if (!map.code)
return ""
if (map.args) {
def formatter = new MessageFormat("")
if (props.getProperty(map.code)) {
formatter.applyPattern props.getProperty(map.code)
}
return formatter.format(map.args.toArray())
} else {
if (props && props.hasProperty(map.code)) {
return props.getProperty(map.code)
} else {
return map.code
}
}
}
}
/**
* add dynamic methods in test setup.
*/
protected void addDynamicMethods() {
registerMetaClass(String)
String.metaClass.mixin StringUtils
}
protected GrailsUser mockGrailsUser() {
return Mock(GrailsUser)
}
...
/**
* must call AFTER mockDpSercurityService
*/
protected void setHasRoleTrue() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return true}
}
}
protected void setHasRoleFalse() {
if (controller?.dpSecurityService?.metaClass) {
controller.dpSecurityService.metaClass.hasRole = {return false}
}
}
protected void mockUserService() {
controller.dpUserService = new MockFor(UserService)
}
}
http://sanjaykanwar.blogspot.com/2012/07/grails-controller-test-with-spock.html
http://naleid.com/blog/2012/05/01/upgrading-to-grails-2-unit-testing
Looks like the if branch gets executed in edit() instead of the else branch because FilterCategory does not get saved and therfore does not get a proper id.