Grails, Integration Testing, mocking a bean method while testing a service with Spock - grails

I'm having an issue performing an integration test in Grails 2.4.5.
The service I want to test looks like this:
class MyService {
def myBean
def serviceMethod() {
myBean.beanMethod()
}
}
where myBean is defined in resources.groovy:
beans = {
myBean(MyBeanImpl)
}
And here comes the integration test:
MyServiceIntegrationSpec extends IntegrationSpec {
def myService
def setup() {
def myBeanMock = Mock(MyBeanImpl)
myBeanMock.beanMethod(_) >> 'foo'
myService.myBean = myBeanMock
}
void "silly test"() {
expect:
myService.serviceMethod() == 'foo'
}
}
Well, this badly fails since myService.serviceMethod() returns null.
I've already tried
ReflectionTestUtils.setField(myService, 'myBean', myBeanMock)
instead of
myService.myBean = myBeanMock
with no luck.
Of course this simplified example could be handled with a unit test, but the real case I'm facing needs an integration test since data persistence is involved.

myBeanMock.beanMethod(_) >> 'foo' expects one parameter.
You can either use
myBeanMock.beanMethod() >> 'foo'
or
myBeanMock.beanMethod(*_) >> 'foo'.
Either case mocking should not be part of Integration spec because this is an integration test. In your case as explained, there might be a need.

Related

Grails integration test mock not cleaned

I've a strange polluting situation between two spock integration tests that I'm not able to resolve. I suppose that I'm doing something wrong but I can't understand what.
The two integration tests are testing different situation of the same controller. In the first one I mock a service while in the second I don't mock.
Here are the significant parts of two tests :
test 1:
// CodeControllerSpec.groovy
...
def controller = new CodeController()
def serviceMock = new MockFor(PollutingService)
serviceMock.demand.search(1) { a, b, c ->
return [id: 1]
}
controller.myService.pollutingService = serviceMock.proxyInstance()
controller.save()
...
then:
serviceMock.verify(controller.myService.pollutingService)
test 2:
// CodeEngineSpec.groovy
...
def controller = new CodeController()
controller.show()
...
then:
...
Controller and services are as following
// CodeController
class CodeController extends RestfulController<Code> {
def myService
def show() {
...
myService.execute()
...
}
}
// MyService
class MyService {
def pollutingService
def execute() {
...
pollutingService.search(a, b, c)
...
}
}
// PollutingService
class PollutingService {
def search(a, b, c) {
...
...
}
}
If I run the two tests one by one, they all pass but, if I run them together, the second one fails with
No more calls to 'search' expected at this point. End of demands.
I'm sure that the mock in the first service is used (I've debugged code line by line) but I don't know why mock is not cleaned after test.
Any suggestion is really welcome.
I'm using grails 2.3.8
First of all, using mocks in integration tests has unpredictable results.
But putting that aside, where is controller.myService in your first test being instantiated? I would have expected that calling controller = new CodeController() would bypass autowiring of controller.myService.

How to Grails 3 integration test in IntelliJ IDEA

I'm not able to run an integration test in IntelliJ IDEA. Here is a test template generated by grails create-integration-test
#Integration
#Rollback
class TestServiceIntSpec extends Specification{
void "test something"() {
//some code here
}
}
Here is the output when I'm trying to run it from junit configuration :
Process finished with exit code 0
Empty test suite.
Also seems like grails using development env if I'm running this test from IDE, I have to specify env explicitly via -Dgrails.env=test
Spock tests ('Specification') identify which methods are tests by the presence of when:, then:, or expect:, etc.
HypeMK's answer is correct. To elaborate, the following test may not run because it does not have the presence of the spock keywords that outline the specification nature of the test (expect, when, then, etc):
#TestFor(BeanFormTagLib)
class BeanFormTagLibSpec extends Specification {
def setup() {}
void "address setup"() {
assertOutputEquals ('Hello World', '<g:beanFormTagLib domainName="com.myapp.Address" />');
}
}
Here we correct the issue by adding the "expect" keyword:
#TestFor(BeanFormTagLib)
class BeanFormTagLibSpec extends Specification {
def setup() {}
void "address setup"() {
expect:
assertOutputEquals ('Hello World', '<g:beanFormTagLib domainName="com.myapp.Address" />');
}
}

Spock does not work for an expected "matched invocations" working through #WebAppConfiguration

I am working with
STS
Gradle
Spock Core
Spock Reports
Spock Spring
Spring MVC Testing
I have the following test code:
#WebAppConfiguration
#ContextConfiguration(classes=[RootApplicationContextConfig.class,ServletApplicationContextConfig.class])
#SuppressWarnings("deprecation")
class PersonaXmlFindOneControllerTest extends Specification {
#Autowired
private WebApplicationContext webApplicationContext;
private MockMvc mockMvc;
private PersonaXmlFindOneController personaXmlFindOneController
def setup(){
mockMvc = MockMvcBuilders.webAppContextSetup(webApplicationContext).build();
personaXmlFindOneController = webApplicationContext.getBean(PersonaXmlFindOneController.class);
println personaXmlFindOneController.toString()
}
def "findOneRequestParamById deberia ser llamado"(){
String url = null
ResultActions resultActions = null
given: "The URL being used "
url = "some url to test"
when: "When the URL is being calling with a GET"
resultActions = mockMvc.perform(get(url, PersonaControllerSupport.ID)).andDo(print())
then: "...."
resultActions.andExpect(status().isOk())
.andExpect(content().contentType(MediaType.APPLICATION_XML))
.andExpect(xpath("persona").exists())
.andExpect(xpath("persona").nodeCount(1))
….
//then:
//1 * personaXmlFindOneController.findOneRequestParamById(_ as String)
}
The code works fine. It pass.
Furthemore: through Gradle Test Report thanks to andDo(print()) I can confirm that personaXmlFindOneController.findOneRequestParamById has been called.
It means
Handler:
Type = com.manuel.jordan.controller.xml.PersonaXmlFindOneController
Method = public com.manuel.jordan.domain.xml.PersonaXml com.manuel.jordan.controller.xml.PersonaXmlFindOneController.findOneRequestParamById(java.lang.String)
Now If enable
//then:
//1 * personaXmlFindOneController.findOneRequestParamById(_ as String)
The code fails,
Too few invocations for:
1 * personaXmlFindOneController.findOneRequestParamById(_ as String) (0 invocations)
Unmatched invocations (ordered by similarity):
None
Observe that in the setup method, it has been retrieved through
personaXmlFindOneController = webApplicationContext.getBean(PersonaXmlFindOneController.class);
Therefore, what is missing or what is wrong?
You are mixing two different mocking mechanisms.
There is the Spring one (MockMVC) and the Spock one.
Spock can only verify mocks created by itself (.i.e those created with the Spock Mock() method). You don't create any Spock mocks in your code and therefore Spock mocking will not work.
See the official documentation of Spock for the full mocking guide to understand how you can create mocks with Spock only.
In your particular example your original code is correct and it should stay that way. You don't always have to use the Spock mocking mechanism. Having a Spock test that uses only Spring testing facilities is perfectly fine.

What is wrong with my Spec?

So, I have this pretty simple Spec below. I have a class that is not a controller or service or anything like that. It's a Job class. It depends on two services: updateService and directoryTypeService. It runs a Redis async job and it's under /grails-app/jobs folder.
All I want is to make sure that whenever I invoke this job#perform() method (which return type is void), a given dependent method called UpdateService#completeClaiming is invoked, but UpdateService#requestNewPin is not. (Listing is a domain class, by the way).
When I run this Spec, I keep getting an error message saying: "No more calls to 'completeClaiming' expected at this point. End of demands."
What am I doing wrong here? Any wild guesses?
#Mock(Listing)
class SubmissionJobSpec extends Specification {
def directoryTypeServiceMock
def updateServiceMock
def job
def setup(){
job = new SubmissionJob()
directoryTypeServiceMock = mockFor(DirectoryTypeService)
updateServiceMock = mockFor(UpdateService)
job.updateService = updateServiceMock.createMock()
job.directoryTypeService = directoryTypeServiceMock.createMock()
}
def "if the directory is enabled and the pin status is ENTERED, we should call updateService.completeClaiming"() {
given:
directoryTypeServiceMock.demand.isUpdateEnabled { DirectoryType d, Country c -> return true}
new Listing(
location: new Location(country: Country.DE)
).save(failOnError: true, validate: false)
when:
job.perform(Listing.last().id, true)
then:
1 * updateServiceMock.completeClaiming(Listing.last(), true) >> new ListingEvent(output: [success: true])
0 * updateServiceMock.requestNewPin(_ as Listing, true)
}
You seem to be confusing Groovy and Spock mocks. You can't use Spock mocking syntax (e.g. 0 * updateServiceMock.requestNewPin(_ as Listing, true)) for a Groovy mock created with mockFor(). Spock mocks are created using Mock(), Stub() or Spy(). I'm not aware of any good reason to use a Groovy mock in a Spock spec.

Grails spock database locking

I have a service method that locks a database row.
public String getNextPath() {
PathSeed.withTransaction { txn ->
def seed = PathSeed.lock(1)
def seedValue = seed.seed
seed.seed++
seed.save()
}
}
This is how my spock test looks like:
void "getNextPath should return a String"() {
when:
def path = pathGeneratorService.getNextPath()
then:
path instanceof String
}
It's just a simple initial test. However I get this error when I run the test:
java.lang.UnsupportedOperationException: Datastore [org.grails.datastore.mapping.simple.SimpleMapSession] does not support locking.
at org.grails.datastore.mapping.core.AbstractSession.lock(AbstractSession.java:603)
at org.grails.datastore.gorm.GormStaticApi.lock_closure14(GormStaticApi.groovy:343)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:302)
at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:37)
at org.grails.datastore.gorm.GormStaticApi.lock(GormStaticApi.groovy:342)
at com.synacy.PathGeneratorService.getNextPath_closure1(PathGeneratorService.groovy:10)
at org.grails.datastore.gorm.GormStaticApi.withTransaction(GormStaticApi.groovy:712)
at com.synacy.PathGeneratorService$$EOapl2Cm.getNextPath(PathGeneratorService.groovy:9)
at com.synacy.PathGeneratorServiceSpec.getNextPath should return a String(PathGeneratorServiceSpec.groovy:17)
Does anyone have any idea what this is?
The simple GORM implementation for Unit tests does not support some features, such as locking. Moving your test to an integration test will use the full implementation of GORM instead of the simple implementation used by unit tests.
Typically when you find yourself using anything more than the very basic features of GORM you will need to use integration tests.
Updated 10/06/2014
In more recent versions of Grails and GORM there is now the HibernateTestMixin which allows you to test/use such features in Unit tests. Further information can be found in the documentation.
As a workaround, I was able to get it working by using Groovy metaprogramming. Applied to your example:
def setup() {
// Current spec does not test the locking feature,
// so for this test have lock call the get method
// instead.
PathSeed.metaClass.static.lock = PathSeed.&get
}

Resources