Grails integration test cannot invoke method on null service object? - grails

Simple service class, AnalyzerService, calls stored proc in a database.
Attempting to run integration test to ensure service calls the stored proc and correct data is returned after analyzer class operates on it. However, getting the dreaded exception that "Cannot invoke method calculateEstimateNumberOfPositions() on null object". Why is the service object null? What am I missing?
THANK YOU!
package foobar.analyze
import static org.junit.Assert.*
import org.junit.*
import foobar.analyze.AnalyzerService
//#TestFor(AnalyzerService)
class AnalyzerServiceTests {
def AnalyzerService service
def dataSource
#Before
void setUp() { }
#After
void tearDown() { }
#Test
void testcalculateEstimateNumberOfPositions() {
String positionName = "crew"
String city = "Great Neck"
String state = "NY"
int numberOfPositionsSought = 100
int expectedNumberOfPositionsEstimate = 100
def numberOfPositionsEstimate = service.calculateEstimateNumberOfPositions(positionName, city, state, numberOfPositionsSought)
fail (numberOfPositionsEstimate != expectedNumberOfPositionsEstimate)
}
}

Convention. Stick to the convention. Anything out of convention, regarding nomenclature, will create problem during dependency injection.
Convention is to use the service class name as analyzerService instead of service in integration test.
The integration test should look like
class AnalyzerServiceTests extends GroovyTestCase {
//Service class injected only if you
//use the naming convention as below for AnalyzerService
def analyzerService
def dataSource
......
......
}
It was possible to use service in unit test case when you use the test mixin
#TestFor(AnalyzerService)
By using the above in unit test cases, you could use the default service variable in the test cases. This is not the same in case of integration tests.

Related

Grails Model Unity Test

I have a "domain"(model) that want to do an Unity Test to check if works.
But when I execute the test I get
java.lang.IllegalArgumentException: Test class can only have one constructor
Thats always happen when trying to initialize a class of some domain(model).
What would be the approach to do correctly the testcase?
class Race {
static constraints = { }
String name
Date startDate
String city
String state
BigDecimal distance
BigDecimal cost
Integer maxRunners = 100000
BigDecimal inMiles() {
return 0.6
}
}
And in the Unity Test Class
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(Race)
class RaceTest extends Specification {
void testInMiles() {
when:
def model = new Race(distance:5.0);
then:
0.6 == model.inMiles()
}
}
In Grails 2.4.x (which is what I'm assuming you're using) the default test type is a Spock test, and that's what's created by the generate-* scripts. You can still write your own tests in JUnit 3 or 4 style if you prefer. But test classes in Spock (at least using the Grails integration, I'm not sure if it's as strict outside of Grails) have to have names ending in "Spec". That's why you're seeing that error.
Test methods do not have to be void and start with "test" (JUnit 3 style) or be void and have an #Test annotation (JUnit 4 style). The test runner decides if a method is a test method if it's public (either explicitly or if there's no scope modifier) and there's at least one labelled block, e.g. when:, given:, then:, etc. Further, Spock uses some AST magic to allow you to use spaces in method names (you just have to quote the whole name) and have expressive, self-descriptive method names, e.g.
def 'an admin without ROLE_SUPER cannot view records of other admins'() {
...
}

Grails 2.4 Command objects nullable constraint and dependency injection

we are preparing for Grails 2.4 upgrade. One of the issues we face is that
most of the command object unit tests fails because of injected properties, like
services, are required to be not null during validation.
Is there any suggested way how to test this? Should we mock all properties although some are not needed for test? or is there a way to do this differently?
After my question is answered by Jeff, I share links with more information about new functionalities:
doWithSpring and doWithConfig are shortly described in What's new in 2.4: http://grails.org/doc/latest/guide/introduction.html#whatsNew24 in Unit Testing improvements section
There is also a JIRA issue with example: https://jira.grails.org/browse/GRAILS-11003
Most unit tests don't want or need the application context all spun up and populated. Unit tests can add whatever they want (or nothing) to the application context. In recent versions of Grails you can do something like this...
A controller and command object:
// grails-app/controllers/demo/DemoController.groovy
package demo
class DemoController {
def processName(SomeCommand co) {
render co.someValue
}
}
class SomeCommand {
String name
def helperService
def getSomeValue() {
helperService.processValue(name)
}
}
A service:
// grails-app/services/demo/HelperService
package demo
class HelperService {
def processValue(String originalValue) {
"__${originalValue}__"
}
}
A unit test:
// grails-app/test/unit/demo/DemoControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(DemoController)
class DemoControllerSpec extends Specification {
def doWithSpring = {
helperService HelperService
}
void 'process name'() {
when:
params.name = 'Jeff'
controller.processName()
then:
response.contentAsString == '__Jeff__'
}
}
That test will pass with Grails 2.4.2.
I hope that helps.

Using Spock to stub both Gorm and other methods in a Grails domain class

Sorry if this is a newbie question but I would really appreciate any insights the community could offer with regard to a problem I am having with stubbing the following method which I have in a Grails service, LocationService.
Location locate(String target, String locator, Application app, boolean sync = true) {
if (!target) throw new IllegalArgumentException("Illegal value for msid: " + target)
def locRequest = Request.create(target, Type.LOCATE)
if (!locRequest.save()) {
return Location.error(target, "Error persisting location request")
}
locationSource.locateTarget(target, locator, app, sync)
}
I have a domain class, Request, that as well as the default GORM methods also has some extra domain methods, eg. the create() method below
#EqualsAndHashCode
class Request {
String reference
String msid
Type type
Status status
Destination destination
DateTime dateCreated
DateTime dateCompleted
static create(String msid, Type type, Destination destination = Destination.DEFAULT) {
new Request(reference: reference(type), type: type, status: Status.INITIATED, dateCreated: new DateTime())
}
Finally, I have a Spock specification. I need to mock both the default GORM methods but also some stub some extra domain logic, eg, a static create method, in order to return a valid object to be persisted in the code under test.
Ideally, I would use Spock mocks but I can't use them here as according to the post below from Peter N, they need to be injected into the caller and in this case the Request (which I am trying to mock), is created as a local variable in the locate method in LocationService:
https://groups.google.com/forum/?fromgroups=#!topic/spockframework/JemiKvUiBdo
Nor can I use the Grails 2.x #Mock annotation as, although this will mock the GORM methods, I am unsure if i can mock/stub the additional static create() method from the Request class.
Hence, finally, I have been trying to use the Groovy StubFor / MockFor methods to do this as I believe that these will be used in the call to the test method by wrapping it in a use closure (as below).
Here is the test spec:
#TestFor(LocationService)
// #Mock(Request)
class LocationServiceSpec extends Specification {
#Shared app = "TEST_APP"
#Shared target = "123"
#Shared locator = "999"
def locationService = new LocationService()
LocationSource locationSource = Mock()
def "locating a valid target should default to locating a target synchronously"() {
given:
def stub = new StubFor(Request)
stub.demand.create { target, type -> new Request(msid: target, type: type) }
stub.demand.save { true }
1 * locationSource.locateTarget(target, locator, app, SYNC) >> { Location.create(target, point, cellId, lac) }
def location
when:
stub.use {
location = locationService.locate(target, locator, app)
}
then:
location
}
However, when I run the test, although the stubbed create method returns my Request stub object, I get a failure on the stubbed save method:
groovy.lang.MissingMethodException: No signature of method: com.domain.Request.save() is applicable for argument types: () values: []
Possible solutions: save(), save(boolean), save(java.util.Map), wait(), last(), any()
Could anybody please point out what I am doing wrong here or suggest the best approach to solve my particular case if needing to stub additional methods as well as GORM methods of a domain class that I can't inject directly into the code under test?
Thank you in advance,
Patrick
I believe you should be able to use Grails' #Mock annotation like you mentioned for the GORM methods, and then you will need to manually mock the static methods:
#TestFor(LocationService)
#Mock(Request)// This will mock the GORM methods, as you suggested
class LocationServiceSpec extends Specification {
...
void setup() {
Request.metaClass.static.create = { String msid, Type type, Destination destination = Destination.DEFAULT ->
//Some logic here
}
}
...
When using the #Mock annotation, Grails will mock the default methods (save/get/dynamic finders), but it doesn't do anything to any additional methods you may have added, so you need to manually mock those.

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/

Grails Dependency Injection Problem

I am having problems when using dependency injection with Services in Grails.
class ExampleService{
def example2Service
def example3Service
def method1(){
def result = example2Service.method2()
}
}
class ExampleService{
def example3Service
def method2(){
def result = example3Service.method3()
return result
}
}
class Example3Service{
def method3(){
return true
}
}
Basically in Example2Service, I am getting a Null Pointer Exception when trying to call method3 in Example3Service.
I would appreciate any help than anybody can give me with this issue
thanks
Dependency Injection needs to be initialized. (The same applies to other kinds of runtime meta programming, like augmenting Domain classes with their save() and validate() methods.)
A Grails application will be initialized when
being run from the grails run-app command
being run after having been deployed to a web server
being run from the grails test-app command (integration tests, only; unit tests do not trigger initialization).
Involved classes are not initialized when
executing a single Groovy file (i.e., by using groovy, groovysh, or groovyConsole)
or when executing a unit test.
The following as an integration test should work:
class Test2ServiceTests extends GroovyTestCase {
def test2Service
void testMethod2() {
assert test2Service.method2() == true
}
}

Resources