Grails - How to instantiate service in Controller when doing controller testing - grails

I am using a service in controller. I am writing unit test for the controller but I am unable to instantiate service in controller. It is always null.
if I instantiate service using new operator in Controller testing class. The services in the service class are not instantiated.
How can I instantiate a service in testing class?

You can let Spring do it for you.
A controller that depends on a service:
// grails-app/controllers/demo/DemoController.groovy
package demo
class DemoController {
def helperService
def index() {
def answer = helperService.theAnswer
render "The answer is ${answer}"
}
}
The service:
// grails-app/services/demo/HelperService.groovy
package demo
class HelperService {
def getTheAnswer() {
42
}
}
A unit test which injects the service:
// src/test/groovy/demo/DemoControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(DemoController)
class DemoControllerSpec extends Specification {
static doWithSpring = {
helperService HelperService
}
void "test service injection"() {
when:
controller.index()
then:
response.text == 'The answer is 42'
}
}
A unit test which injects a fake version of the service:
// src/test/groovy/demo/AnotherDemoControllerSpec.groovy
package demo
import grails.test.mixin.TestFor
import spock.lang.Specification
#TestFor(DemoController)
class AnotherDemoControllerSpec extends Specification {
static doWithSpring = {
helperService DummyHelper
}
void "test service injection"() {
when:
controller.index()
then:
response.text == 'The answer is 2112'
}
}
class DummyHelper {
def getTheAnswer() {
2112
}
}

Related

Micronaut #Replaces with declarative Client

I am going to use the code from Micronaut Documentation (Declarative Http Client)- And I'm using Spock
PetOperations.java
#Validated
public interface PetOperations {
#Post
Single<Pet> save(#NotBlank String name, #Min(1L) int age);
}
I have a declarative client:
#Client("/pets")
public interface PetClient extends PetOperations {
#Override
Single<Pet> save(String name, int age);
}
My goal is when I run a test class, I want to call (#Replaces) another class (PetDummy) instead of the PetClient, PetDummy class is located in my test folder
#Primary
#Replaces(PetClient.class)
#Singleton
public class PetDummy implements PetOperations {
#Override
public Single<Pet> save(String name, int age) {
Pet pet = new Pet();
pet.setName(name);
pet.setAge(age);
// save to database or something
return Single.just(pet);
}
}
test class:
class PetTest extends Specification {
#Shared
#AutoCleanup
ApplicationContext applicationContext = ApplicationContext.run();
//EmbeddedServer server = applicationContext.getBean(EmbeddedServer.class).start();
PetClient client = applicationContext.getBean(PetOperations.class);
def 'test' (){
given: 'name and age'
when:
client.save("Hoppie", 1);
then:
noExceptionThrown()
}
}
However, at the end PetClient is called, I have as well tried with the #Factory annotation, but no success
PetClient extends PetOperations and PetDummy implements PetOperations, if they both implement then it will make sense to use #Replaces ...
Is there something else I can try out?
Thank you!
Another Issue:
Now that it works, the PetClient is a dependency in my PetService. When I test my PetService, it still calls the PetClient instead of the PetDummy.
I assume it has to do with the applicationContext, you will see
PetService:
PetService {
#Inject
PetClient client;
buyFood(){
//...
Single<Pet> pet = client.save("Hoppie", 1));
}
}
PerService Test:
class PetServiceTest extends ApplicationContextSpecification {
#Subject
#Shared
PetService petService = applicationContext.getBean(PetService)
PetOperations client = applicationContext.getBean(PetOperations.class) //client is not used here
def 'test' (){
given:
when:
petService.buyFood()
then:
noExceptionThrown()
}
}
I think that I need to "get into" the applicationContext from the PetService, to tell "use the PetDummy" implementation (Inside the test class, because the ApplicationContextSpecification belong to another module
The ApplicationContextSpecification is:
abstract class ApplicationContextSpecification extends Specification implements ConfigurationFixture {
#AutoCleanup
#Shared
ApplicationContext applicationContext = ApplicationContext.run(configuration)
/* def cleanup() {
assert !hasLeakage()
}*/
}
The ConfigurationFixture contains the properties for the database(hibernate)
You are already retrieving the PetClient bean implementation:
PetClient client = applicationContext.getBean(PetOperations.class);
Which should provide the replacing dummy bean implementation if called with the appropriate type:
PetOperations client = applicationContext.getBean(PetOperations.class);

grails restful groovy can not resolve symbol

I am trying to learn grails by following the link: https://guides.grails.org/rest-hibernate/guide/index.html and after creating the controller ProductController as per the page's guidance I am getting the following error:
Unable to resolve class ProductService in ProductController
I new to groovy and trying to resolve the class reference by importing the necessary packages but the link does not show any imports to resolve this class. there is not explicit import statement for ProductService productService in ProductController.groovy. Here are the classes:
ProductController:
package hibernate.example
import groovy.transform.CompileStatic
import grails.rest.*
import grails.converters.*
#CompileStatic
class ProductController extends RestfulController {
static responseFormats = ['json', 'xml']
ProductController() {
super(Product)
}
ProductService productService
def search(String q, Integer max ) {
if (q) {
respond productService.findByNameLike("%${q}%".toString(), [max: Math.min( max ?: 10, 100)])
}
else {
respond([])
}
}
}
ProductControllerSpec:
package hibernate.example
import org.grails.testing.GrailsUnitTest
import spock.lang.Specification
#SuppressWarnings('MethodName')
class ProductControllerSpec extends HibernateSpec implements ControllerUnitTest<ProductController> {
def setup() {
}
def cleanup() {
}
static doWithSpring = {
jsonSmartViewResolver(JsonViewResolver)
}
void 'test the search action finds results'() {
given:
controller.productService = Stub(ProductService) {
findByNameLike(_, _) >> [new Product(name: 'Apple', price: 2.0)]
}
when: 'A query is executed that finds results'
controller.search('pp', 10)
then: 'The response is correct'
response.json.size() == 1
response.json[0].name == 'Apple'
}
}

Inject property into integration test Grails 3

How does one inject properties from the applicaiton.yml file into an integration test in grails 3.0 ?
For ex: I have this property in my applicaiton.yml
----
testing:
defaults:
startUrl: 'http://localhost:8080/'
----
In my Integration Spock test, I have the following code:
class WebpageRolesTestSpec extends Specification {
def grailsApplication
String LOGIN_URL = grailsApplication.config.getProperty('testing.defaults.startUrl')
void "test login screen prompt"() {
expect:
LOGIN_URL == 'http://localhost:8080/'
}
}
The exception i am getting is: Cannot get property 'config' on null object
You could use holders:
import grails.util.Holders
...
LOGIN_URL = Holders.config.testing.defaults.startUrl
...
Below test works for me in Grails 3.1.1, I suppose you would need a clean app.
import grails.test.mixin.integration.Integration
import grails.transaction.*
import spock.lang.*
#Integration
#Rollback
class SampleSpec extends Specification {
def grailsApplication
void "test something"() {
expect:"fix me"
grailsApplication.config.getProperty('testing.defaults.startUrl') ==
'http://localhost:8080/'
}
}

Grails 3 mail plugin not working

Using Grails 3 it's impossible to get an instance of mailService object, DI is not working:
build.gradle
compile "org.grails.plugins:mail:1.0.7"
testCompile "org.grails.plugins:mail:1.0.7"
application.groovy
environments {
development {
//grails.logging.jul.usebridge = true
grails.plugin.springsecurity.debug.useFilter = true
grails {
mail {
host = "main.mydomain.com"
port = 25
username = "login"
password = "password"
props = ["mail.smtp.auth":"true"]
}
}
grails.mail.default.from="noreply#mydomain.com"
}
production {
grails.logging.jul.usebridge = false
}
}
testController:
import groovy.xml.MarkupBuilder
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.security.access.annotation.Secured
#Secured(["hasRole('PERM_LOGIN')"])
class TestLogController {
def Logger logger = LoggerFactory.getLogger(this.getClass())
def mailService
def index() {
logger.info("Hello");
mailService.sendMail {
to "user#daomain.com"
subject "Hello Fred"
text "How are you?"
}
}
}
The following error occurs:
Caused by NullPointerException: Cannot invoke method sendMail() on null object
->> 18 | index in TestLogController.groovy
So mailService has not been injected properly to cotroller class or to integration test:
import grails.test.mixin.integration.Integration
import grails.util.Holders
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.context.ApplicationContext
import spock.lang.Shared
import spock.lang.Specification
#Integration
class SendMailSpec extends Specification {
#Shared Logger logger
#Shared def mailService
def setup() {
logger = LoggerFactory.getLogger(this.getClass())
ApplicationContext ctx = Holders.grailsApplication.mainContext
mailService = ctx.getBean("mailService");
}
def cleanup() {
}
void "test mailService is not null"() {
expect:
mailService !=null
}
void "test send mail"() {
expect:"mail send"
mailService.sendMail {
to "user#domain.com"
subject "Hello Fred"
text "How are you?"
}
}
}
What is a problem ??
UPDATE: It was wrong mail plugin version, this one works fine:
compile "org.grails.plugins:mail:2.0.0.RC2"
here's the current version (at the moment of writing this) to install :
compile 'org.grails.plugins:mail:2.0.0.RC6'
Here's the link to the main plugin (I don't know why google shows only the old versions) :
https://grails.org/plugins.html#plugin/mail
I hope this helps someone

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

Resources