Do GORM hook methods work in Grails integration test - grails

I have simple question
Do GORM hooks method (beforeUpdate, afterLoad etc) work during integration tests? Are they evaluated?
I have integration test (my test class extends GroovyTestCase) and as I can see changes that I make in afterLoad method on my domain object doesn't seem to work (domain object stays the same after loading) and when I test it manually (run my app) it works (domain object is changed successfully). Also I cannot see any logs or prints to console from hook methods during integration tests.
Is this expected behavior or I am missing something?
Here is some code:
I have PackageState domain object which has field accountID (Integer).
In PackageState I have afterLoad hook:
def afterLoad() {
this.accountID = 33333
}
My test suite looks something like this :
void "test3"() {
PackageState packageState1 = PackageState.findByAccountID(11111)
assertEquals(33333, packageState1.accountID)
}
Message is :
junit.framework.AssertionFailedError: expected:<33333> but was:<11111>
So seems to me that hook is not called :/ ...
Thanks,
Ivan

You can integration test those event hooks by surrounding the dynamic method (or any other GORM method) by withNewSession as:
class PackageStateSpec extends IntegrationSpec {
PackageState packageState1
void "test something"() {
given:
PackageState.withNewSession{
packageState1 = PackageState.findByAccountID(11111)
}
expect:
packageState1.accountID == 33333
}
}
Events will be registered with a new session every time when tested from integration tests.

Related

Grails dynamic methods not present when running integration tests

I'm working on a project using Grails 2.5.4 and I'm currently trying to run some integration tests that are not running.
I've debugged the issue and found that apparently some dynamic methods on the services to be tested are not there when running in an integration test (if you run that in the context of the application the methods are there and everything works). This happens in many of the test I'm trying to run, I've choose one as an example but the others that are failing have the same problems.
I have this domain class
class Event {
...
static hasMany = [
bundles : Bundle
]
...
}
and a service method to be tested:
#Transactional
class BundleService {
...
void assignEvent(Event event, List bundleIds) {
..
for (id in bundleIds) {
event.addToBundles(Bundle.get(id))
}
}
...
}
So then I run this spock test
class BundleServiceIntegrationSpec extends Specification {
BundleService bundleService
EventService eventService
private BundleTestHelper bundleHelper = new BundleTestHelper()
...
void '04. Test deleteBundleAndAssets method'() {
when: 'a new Bundle is created'
Bundle bundle = bundleHelper.createBundle(project, 'Test Bundle')
and: 'a new Event is created'
Event event = eventService.create(project, 'Test Event')
and: 'the above Bundle is assigned to the Event'
bundleService.assignEvent(event, [bundle.id])
...
}
it fails in the line moveEvent.addToBundles(Bundle.get(id)) of BundleService with the following exception
groovy.lang.MissingMethodException: No signature of method:
net.domain.Event.addToBundles() is applicable for argument
types: (net.domain.Bundle) values: [Test Bundle]
Possible solutions: getBundles()
at net.service.BundleService.$tt__assignEvent(BundleService.groovy:101)
The problem is that the method addToBundles() that should be added dynamically by Grails to the Event class because of the hasMany collection "bundles" is not added. As I mentioned, if you run the application and use this service the method is there and everything works.
I tried changing the base class of the test (from Specification to IntegrationSpec) since I belive here is where the dynamic capabilities as well as transaction management and other things for integration tests are managed, but it didn't worked.
Is there any reason why this method that should be there in the service is not present in the context of integration tests? Thanks
You are missing grails.test.mixin.Mock annotation in your test class. Grails unit test uses this mixin to generate all domain related methods for a class so you can use this domain correctly in the unit test. Something like this should do the trick:
#Mock([Event])
class BundleServiceIntegrationSpec extends Specification {
BundleService bundleService
EventService eventService
private BundleTestHelper bundleHelper = new BundleTestHelper()
...
void '04. Test deleteBundleAndAssets method'() {
when: 'a new Bundle is created'
Bundle bundle = bundleHelper.createBundle(project, 'Test Bundle')
and: 'a new Event is created'
Event event = eventService.create(project, 'Test Event')
and: 'the above Bundle is assigned to the Event'
bundleService.assignEvent(event, [bundle.id])
...
}
More about testing domain classes can be found here: https://grails.github.io/grails2-doc/2.4.5/guide/testing.html#unitTestingDomains
#Szymon Stepniak Thanks for your answer, and sorry for the late reply. I've tested what you proposed but it didn't work. Later I've read that the
grails.test.mixin.Mock annotation is only for unit tests, and it should not be used in integration tests. This is also true for #TestFor and #TestMixin annotations as well (I've read about this in this post).
So after this a collegue at work proposed me to search for this kind of annotations in other tests thinking that maybe that could lead to some kind of test pollution between tests, and after removing a #TestFor annotation in one of the tests that ran previously as part of the whole integration test suite, the failing test that I posted started working. The strangest thing (appart from the compiler not complaining about this) is that the offending test (the one from which I removed the #TestFor annotation) was passing all green, it wasn't even failing!
So if someone has a similar problem I suggest to search for this kind of unit test annotations anywhere in the whole integration tests suite and remove it because the compiler won't complain, but in my experience it could have influence on other tests and it can lead to very strange behaviour.

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
}
}

Grails integration test setUp and junit annotation

I have some executeQuery in the code for complex group by/having clause so I need an integration test case to test it. Grails 2.1.1 was used.
However, I found several issues:
1. the setUp method is not called automatically before the test.
2. So I add #Before annotation to the setUp method and it can be called now. But the executeQuery statement can't be used now.
java.lang.UnsupportedOperationException: String-based queries like [executeQuery] are currently not supported in this implementation of GORM. Use criteria instead.
It seems I can't use any annotation in the integration test. Otherwise it becomes a unit test case? If I don't use any annotation, the test passed.
Here is the code example.
class JustTests extends GroovyTestCase {
void setUp() {
log.warn "setup"
}
void tearDown() {
log.warn "cleanup"
}
void "test something"() {
// Here is the code to invoke a method with executeQuery
}
}
Thanks.

Changing autoGenerating Grails Test Scaffold to Spock Test

Hi i m trying to change the auto-generated testCases in grails
#TestMixin(GrailsUnitTestMixin)
class KLAKSpec {
void setUp() {
// Setup logic here
}
void tearDown() {
// Tear down logic here
}
void testSomething() {
fail "Implement me"
}
}
to Spock Type test format which is something like this
#TestFor(GrailsUnitTestCase)
class #artifact.name# extends #artifact.superclass# {
def "feature method"() {
setup:
when:
then:
where:
}
}
Althought i have added a _Events.groovy script under the scipt folder and added a Spec.groovy file in artifacts folder which changes the name when i auto generate the list.
Can any one please let me knw how i can change to spec format.
I wrote a blog post on this some time ago: Auto-generate Spock specs for Grails artifacts. The post was written pre-Grails 2 so it's still using the old superclasses rather than #TestFor but it should be easy enough to adapt. We still use this technique on our project where we're still on Grails 1.3.7. It's a bit of a blunt instrument as Grails doesn't expose a unique event for test generation but it works fine.

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