Grails integration test on a service: cannot set property on null object - grails

I am using Grails 2.4.4 for my application, and using spock framework for tests.
class TaxpayerService {
static transactional = false
def springSecurityService
def setImporterDetails(TvfGen tvfGen) {
if (isTrader()) {
String taxPayerCode = springSecurityService?.principal?.getAt("tin")
def importerDetails = HistorizationSupport.withHistorizedFinder(BusinessLogicUtils.getWorkingDate(tvfGen)) {
Company.findByCode(taxPayerCode)
}
if (importerDetails) {
tvfGen.with {
impTaxPayerAcc = taxPayerCode
impName = importerDetails.name
}
}
}
}
}
Here is my integration test:
#Build([TvfGen])
class TaxpayerServiceSpec extends IntegrationSpec {
def taxpayerService
def springSecurityService
void setup() {
}
void tearDown() {
// Tear down logic here
}
void "test set importer details"() {
given:
def tvfGen = TvfGen.build()
springSecurityService = [principal: [tin: '0815790B', authorities: [ROLE_TRADER]]]
taxpayerService.springSecurityService = springSecurityService
taxpayerService.setImporterDetails(tvfGen)
expect:
tvfGen.impName == 'OMNI VALUE'
}
}
As a result I receive an error:
Cannot set property 'springSecurityService' on null object
java.lang.NullPointerException: Cannot set property 'springSecurityService' on null object
at TaxpayerServiceSpec.test set importer details(TaxpayerServiceSpec.groovy:34)

Related

Existing transaction detected in JobRepository - Spring Batch with Grails Plugin

Every time I start my batch job it throws an IllegalStateException and says it detected a transaction in JobRepository. I did some research and removed all #Transactional annotations in my code.
I use the Grails Spring Batch Plugin you can find here, and I work with Grails 2.3.11 and Java 8. My code looks like this:
SimpleJobBatchConfig.groovy
beans {
xmlns batch:"http://www.springframework.org/schema/batch"
batch.job(id: 'simpleJob') {
batch.step(id: 'printStep') {
batch.tasklet(ref: 'printHelloWorld')
}
}
printHelloWorld(SimpleJobTasklet) { bean ->
bean.autowire = 'byName'
}
}
BatchTestController.groovy
class BatchelorController {
def batchTestService
def index() {
}
def launchSimpleJob() {
batchTestService.launchSimpleJob()
}
}
BatchTestService.groovy
class BatchTestService {
def springBatchService
def launchSimpleJob() {
springBatchService.launch("simpleJob")
}
}
SimpleJobTasklet.groovy
class SimpleJobTasklet implements Tasklet {
#Override
RepeatStatus execute(StepContribution stepContribution, ChunkContext chunkContext) throws Exception {
println("Hello World!")
return RepeatStatus.FINISHED
}
}
Grails services are transactional by default. You can customize the settings for the whole class or per-method with #Transactional but if you have no annotations it's the same as having a class-scope Spring #Transactional annotation.
To make your service non-transactional, add static transactional = false, e.g.
class BatchTestService {
static transactional = false
def springBatchService
...
}
}

Grails code coverage not working

I am using Grails 2.2.4 and create JUnit Test for controller but code coverage not cover my test case of controller below are my test case detail.
//BuildConfig.groovy
plugins {
test ":code-coverage:2.0.3-3"
}
//MyControllerTests.groovy
#TestMixin(GrailsUnitTestMixin)
#TestFor(MyController)
#TestFor([Domain1,Domain2])
class MyControllerTests {
void setUp() {
controller.myService = new MyService()
}
void testAction1(){
controller.action1()
}
}
//mycontroller.groovy
class MyController {
def myService
def action1{
def msg = myService.myFirstAction()
}
}
//myservice.groovy
class MyService{
def myFirstAction(){
//logic which returns string
return 'my logic result'
}
}

In a unit test, how can I replace a interface method on a domain object?

I'm using Groovy 1.8.6 and Grails 2.1.1
I have a interface
public interface Searchable{
Long docVersion()
}
Implemented by a object
class Book implements Searchable {
Long docVersion() {
System.currentTimeMillis() / 1000L
}
String otherMethod() {
"toto"
}
}
And a test
#Mock([Book])
class SomeBookTester {
#Before
void setup() {
Book.metaclass.docVersion = {-> 12345}
Book.metaclass.otherMethod = {-> "xyz"}
}
#Test
void test1() {
assert 12345 == new Book().docVersion()
}
#Test
void test2() {
assert "xyz" == new Book().otherMethod()
}
}
The first test always fail because the methode replacement dosen't work. How could I fix this? What's the probleme?
You better use a proper GrailsMock facilities. You may try this:
#Mock([Book])
class SomeBookTester {
#Before
void setup() {
def mockBook = mockFor(Book)
mockBook.demand.docVersion(0..1) { -> 12345 }
mockBook.demand.otherMethod(0..1) { -> "xyz" }
Book.metaClass.constructor = { -> mockBook.createMock() }
}
#Test
void test1() {
assert 12345 == new Book().docVersion()
}
#Test
void test2() {
assert "xyz" == new Book().otherMethod()
}
}
This works for me
I change the class like that:
class Book implements Searchable {
Long docVersion() {
currentTime()
}
Long currentTime() {
System.currentTimeMillis() / 1000L
}
String otherMethod() {
"toto"
}
}
And in the test, I replace the currentTime method
#Mock([Book])
class SomeBookTester {
#Before
void setup() {
Book.metaclass.currentTime= {-> 12345}
Book.metaclass.otherMethod = {-> "xyz"}
}
#Test
void test1() {
assert 12345 == new Book().docVersion()
}
#Test
void test2() {
assert "xyz" == new Book().otherMethod()
}
}
Tests passes

Does using #Transactional disable the grails default transaction management

According to the grails docs, services are transactional by default. But, I know you can get more fine grained control of transactions by using the Transactional attribute.
If I have a service such as
class MyService {
#Transactional(...config...)
def method1() { }
def method2() { }
}
My understanding is that in this case, method1 will be transactional, but method2 will not.
If I have
class MyService {
def method1() { }
def method2() { }
}
Then both method1 and method2 will both be transactional.
Is this correct?
If you want your service as transactional set to true the transactional property (this isn't obligatory but if you want to make clear that the service is transactional):
class MyService {
static transactional = true
def method1() { }
def method2() { }
}
If you don't want to:
class MyService {
static transactional = false
#Transactional(...config...)
def method1() { }
def method2() { }
}
Another example (setting transactional property isn't obligatory, but helps to be clear - if you are not the only coding this):
import org.springframework.transaction.annotation.Transactional
class BookService {
#Transactional(readOnly = true)
def listBooks() {
Book.list()
}
#Transactional
def updateBook() {
// …
}
def deleteBook() {
// …
}
}
Another thing you can do is annotate the whole class and override the methods you need to be different:
import org.springframework.transaction.annotation.Transactional
#Transactional
class BookService {
#Transactional(readOnly = true)
def listBooks() {
Book.list()
}
def updateBook() {
// …
}
def deleteBook() {
// …
}
}
Hope this helps ;)
You can disable the Grails default transaction management using withTransaction closure for domains to manage your Transaction manually as follows:
Account.withTransaction { status ->
try {
//write your code or business logic here
} catch (Exception e) {
status.setRollbackOnly()
}
}
If an exception is thrown, then the Transaction will be rollbacked.

idiom for save and update methods in grails

Are there in any idioms in grails which help us with saving domain objects ?
For example
i may want to do something like
if(candidate.hasErrors || !candidate.save)
{
candidate.errors.each {
log it
}
However i do not want to spread the logic across all the places i do domainObject.save.
I also do not want seperate class like say repo to which I pass this domainObject and put in this logic
Thanks
Sudarshan
Here's a service method that I've used to validate and save, but log resolved validation messages on failure. It's helpful to use this instead of just println error or log.warn error since the toString() for error objects is very verbose and you just want to see what would be displayed on the GSP:
class MyService {
def messageSource
def saveOrUpdate(bean, flush = false) {
return validate(bean) ? bean.save(flush: flush) : null
}
boolean validate(bean) {
bean.validate()
if (bean.hasErrors()) {
if (log.isEnabledFor(Level.WARN)) {
def message = new StringBuilder(
"problem ${bean.id ? 'updating' : 'creating'} ${bean.getClass().simpleName}: $bean")
def locale = Locale.getDefault()
for (fieldErrors in bean.errors) {
for (error in fieldErrors.allErrors) {
message.append("\n\t")
message.append(messageSource.getMessage(error, locale))
}
}
log.warn message
}
bean.discard()
return false
}
return true
}
And here's an example in a controller:
class MyController {
def myService
def actionName = {
def thing = new Thing(params)
if (myService.saveOrUpdate(thing)) {
redirect action: 'show', id: thing.id
}
else {
render view: 'create', model: [thing: thing]
}
}
}
Edit: It's also possible to add these methods to the MetaClass, e.g. in BootStrap.groovy:
class BootStrap {
def grailsApplication
def messageSource
def init = { servletContext ->
for (dc in grailsApplication.domainClasses) {
dc.metaClass.saveOrUpdate = { boolean flush = false ->
validateWithWarnings() ? delegate.save(flush: flush) : null
}
dc.metaClass.validateWithWarnings = { ->
delegate.validate()
if (delegate.hasErrors()) {
def message = new StringBuilder(
"problem ${delegate.id ? 'updating' : 'creating'} ${delegate.getClass().simpleName}: $delegate")
def locale = Locale.getDefault()
for (fieldErrors in delegate.errors) {
for (error in fieldErrors.allErrors) {
message.append("\n\t")
message.append(messageSource.getMessage(error, locale))
}
}
log.warn message
delegate.discard()
return false
}
return true
}
}
}
}
This depends on a 'log' variable being in scope, which will be true in any Grails artifact. This changes the controller usage slightly:
class MyController {
def actionName = {
def thing = new Thing(params)
if (thing.saveOrUpdate()) {
redirect action: 'show', id: thing.id
}
else {
render view: 'create', model: [thing: thing]
}
}
}
As a metaclass method it may make more sense to rename it, e.g. saveWithWarnings().

Resources