Grails inject Service into Controller dependant on environment - spring

I have a situation in a Controller where I'm surrounding pieces of code in if(Environment.Current == Environment.PRODUCTION) blocks because the block of code is calling methodA in restService that makes a REST call to a URL that is only available when the app is deployed onto a specific production server. However doing so means that area of code is unreachable when running tests, which makes me a bit uncomfortable.
In the Development environment I'm not concerned with making the call to methodA as I'm stubbing out what the methodA would return and passing it on to the next Controller, so changing the if statement to if(Environment.Current != Environment.DEVELOPMENT) allows me to test the code better and not have to make calls to places I can't reach during dev.
Ideally though I would like to try and inject a Service into a Controller dependent on the grails environment; so I could have two Services like this:
class RestService {
def methodA() {
// go do a REST call
}
}
and
class FakeRestService() {
def methodA() {
// return some stubbed response
}
}
and in my Controller restService would be an instance of FakeRestService in DEVELOPMENT and TEST environments, and an instance of RestService in PRODUCTION
class SearchController {
def restService
def index() {
restService.methodA()
}
I'm a bit stumped on how I could achieve this in a 'Grailsy'/Spring way. I've been looking into creating some sort of Service Factory which would return an instance of either RestService or FakeRestService dependent on the environment, but it would be nice if I could define what Service to inject into restService in config or something similar.
Any advice would be great!

You can add an alias for the bean name in resources.groovy when environment is TEST.
import grails.util.Environment
beans = {
if ( Environment.current == Environment.TEST ) {
springConfig.addAlias 'restService', 'fakeRestService'
}
}
RuntimeSpringConfiguration is available in resources.groovy by getSpringConfig().

Here is a more Grails-y version of dmahapatro's answer:
import grails.util.Environment
beans = {
Environment.executeForCurrentEnvironment {
environments {
development {
springConfig.addAlias 'restService', 'fakeRestService'
}
}
}
}

Related

Using Service methods inside Utils class [Spring and Kotlin]

I have faced a well-known scenarios whereby I really need to move a number of utilities private functions (that should not have been there in the first place) from my Service class to a utility class. My question is around using service methods in a utility class. I have attempted at the following refactoring:
class Utils(
val serviceIneed : ServiceIneed) {
companion object {
private val someMapper = ObjectMapperConfig.mapper
}
fun someUtility(): ResponseEntity<Any> {
// lots of stuff
return serviceIneed.someFunction()
}
}
Then this is the other service where I need to use the method I have moved to the newly created utility class:
class anotherService(
private val serviceIneed: ServiceIneed
) {
fun someMethod() {
// lots of things happening
val utilityUsage = Utils(serviceIneed).someUtility()
}
}
Is this the correct way to go about this? Can you recommend any approach on refactoring service classes in a way that only service-oriented methods and not helper ones remain in my Service class?
Thank you

How to initialise/wire beans in Grails Spock unit tests?

I'm wanting to test a Grails controller that contains a bean (I'll move it to a Service when I get it working, but I just want to keep it simple now).
//resources.groovy
beans {
myBean(com.me.MyBean)
}
// MyBean.java
// this needs to be in java as it is playing with spring-data-neo4j
package com.me;
public class MyBean {
String show() {
return "Hello";
}
}
// TestController.groovy
package com.me
import com.me.MyBean
class TestController {
def myBean
def index() {
render myBean.show()
}
}
// TestControllerSpec.groovy
package com.me
import grails.test.mixin.TestFor
import spock.lang.Specification
import com.me.*
#TestFor(TestController)
class TestControllerSpec extends Specification {
def myBean
def setup() {
defineBeans {
myBean(com.me.MyBean) {bean->
bean.autowire = true
}
}
}
def cleanup() {
}
def "show() returns Hello"() {
when:
def rc = controller.myBean.show()
def rc2 = myBean.show()
then:
rc == "Hello"
rc2 == "Hello"
}
}
Within TestControllerSpec, myBean is null. controller.myBean is also null. I think this is because Spring is not picking the bean up and wiring it in. I gather that in unit tests not all spring beans are available, but what do I need to do to get controller.myBean to be instantiated and wired up correctly?
You must be mocking the myBean as below
def myBean = Mock(MyBean)
or
MyBean myBean = Mock()
and then stub out method for your need if required as below:
myBean.show >> "test data"
and then assign it to controller object which is already mocked for you.
controller.myBean = myBean
and there you go.
Or optionally you can stub out myBean and give stubbed implementations. For example,
MyBean myBean = Stub(){
show() >> {return "sample text"}
}
controller.myBean = myBean
The reason for doing this is we are not testing the integration of application entities like controller, views or domain but we are testing a single unit i.e. a method and hence we should be just testing it and for integration we should be using integration test cases which would be similar in everything except you won't require any mocking in normal scenarios.
Edit:
found another useful feature to mock services or beans using defineBeans closure as below:
defineBeans {
adapter(Adapter)
helperService(HelperService)
}
This will allow beans to be accessed from grailsApplication.
Hope it helps.

How to dynamically select a service in Grails

From my controller I would like to dynamically select a service based on a parameter.
Currently I have a base service and some other services that extent this base service. Based on the parameter I call a class that does creates a bean name based on the param and eventually calls the following:
import org.codehaus.groovy.grails.web.context.ServletContextHolder as SCH
import org.codehaus.groovy.grails.web.servlet.GrailsApplicationAttributes as GA
class Resolver {
def ctx
def getBean(String beanName) {
if(!ctx) {
ctx = SCH.servletContext.getAttribute(GA.APPLICATION_CONTEXT)
}
return ctx."${beanName}"
}
}
This returns the service I want. However I feel rather dirty doing it this way. Does anyone have a better way to handle getting a service (or any other bean) based on some parameter?
Thank you.
ctx."${beanName}" is added to the ApplicationContext metaclass so you can do stuff like def userService = ctx.userService. It's just a shortcut for ctx.getBean('userService') so you could change your code to
return ctx.getBean(beanName)
and it would be the same, but less magical.
Since you're calling this from a controller or a service, I'd skip the ServletContextHolder stuff and get the context by dependency-injecting the grailsApplication bean (def grailsApplication) and getting it via def ctx = grailsApplication.mainContext. Then pass it into this helper class (remember the big paradigm of Spring is dependency injection, not old-school dependency-pulling) and then it would be simply
class Resolver {
def getBean(ctx, String beanName) {
ctx.getBean(beanName)
}
}
But then it's so simple that I wouldn't bother with the helper class at all :)

Unit testing with Mockito

I am writing unit tests for service layer in my spring application.
Here is my service class
#Service
public class StubRequestService implements RequestService {
#Autowired
private RequestDao requestDao;
#Transactional(propagation = Propagation.REQUIRED, readOnly = true)
#Override
public Request getRequest(Long RequestId) {
Request dataRequest = requestDao.find(requestId);
return dataRequest;
}
}
Here is my test class
#RunWith(MockitoJUnitRunner.class)
#ContextConfiguration(locations = { "/META-INF/spring/applicationContext.xml" })
public class StubRequestServiceTest {
#Mock
public RequestDao requestDao;
StubRequestService stubRequestService; // How can we Autowire this ?
#org.junit.Before
public void init() {
stubRequestService = new StubRequestService(); // to avoid this
stubRequestService.setRequestDao(dataRequestDao);
// Is it necessary to explicitly set all autowired elements ?
// If I comment/remove above setter then I get nullPointerException
}
#Test
public void testGetRequest() {
Request request = new Request();
request.setPatientCnt("3");
when(requestDao.find(anyLong())).thenReturn(request);
assertEquals(stubRequestService.getRequest(1234L).getPatientCnt(),3);
}
}
Its working fine but I have few questions
How can we Autowire service class in test ? I am using constructor in init() method to create service object.
Do we have to set all Autowire element for service class ? For ex StubRequestService have autowired RequestDao which I need to set explicitly before calling test method otherwise it giveds nullPointerException as requestDao is null in StubRequestService.getRequest method.
Which are the good practices to follow while unit testing Spring service layer ? (If I am doing anything wrong).
Your test is fine. It doesn't even have to have the #ContextConfiguration annotation.
The whole point of dependency injection frameworks like Spring is to be able to unit test services by simply instantiating them, setting mock dependencies, and then call their methods.
You're doing it correctly. You don't need to have a Spring context for such unit tests. That's why they're called unit tests: they test it in isolation of all their actual dependencies, Spring included.
Side note: assuming you're using JUnit, the arguments of the assertXxx method should be swapped. The expected value comes before the actual value. It becomes important when the assertion fails and you have a message like "expecting 6 but was 3" rather than "expecting 3 but was 6".
If you really feel that it will make your tests easier to understand - you can initialize a spring context and fetch all of the objects from there. However, usually it will require creating a separate spring configuration XML file specifically for tests therefore I would not recommend it.
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("testApplicationContext.xml");
stubRequestService = (RequestService)applicationContext.getBean("myRequestServiceBean");
(and 3) Basically, I prefer testing each component of my application in total isolation from eachother and that's why I do not recommend what I described in [1].
What that means, is you take a separate logical slice of your application and test only it, while fully mocking up everything it tries to access.
Let's say you have three classes:
//Fetches stuff from some webservice and converts to your app domain POJOs
class DataAccessLayer {
public void setWebservice(Webservice ws) {...};
public MyObject getMyObject() {...};
}
//Formats the domain POJOs and sends them to some kind of outputstream or stuff.
class ViewLayer {
public void setOutputStream(OutputStream os) {...};
public void viewMyObject(MyObject mo) {...};
}
//Main entry point of our MyObject fetch-process-display workflow
class Controller {
public void setDataAccessLayer(DataAccessLayer dal) {...};
public void setViewLayer(ViewLayer vl) {...};
public void showMyObject() {
MyObject mo = dal.getMyObject();
...some processing here maybe...
vl.viewMyObject(mo);
}
}
Now, what tests can we write here?
Test if DataAccessLayer properly converts the object from mocked up WS to our domain object.
Test if ViewLayer properly formats the object given to him and writes it to mocked up output stream.
Test if Controller takes an object from mocked up DataAccessLayer processes it properly and sends it to mocked up ViewLayer.
Or You can use springockito
https://bitbucket.org/kubek2k/springockito/wiki/Home, it will make your tests cleaner

Grails domain class initialization

My Grails app has the following Spring bean defined in spring/resources.groovy
calendarService(CalendarService) { bean ->
bean.initMethod = "init"
}
This method looks something like:
class CalendarService {
void init() {
User.findByEmail("foo#doo.com")
}
}
When I call the dynamic finder findByEmail I get a MissingMethodException. My guess is that I'm trying to call this method too early, i.e. before the domain classes have had the dynamic finders added to their metaclass. One solution would be to call CalendarService.init() myself from Bootstrap.init, rather than instructing Spring to call it, but is there a better solution?
Thanks,
Don
You're right, as described in this post, if you need the dynamic methods you'd better go with BootStrap.groovy
BootStrap {
def calendarService
def init() {
calendarService.init()
}
}
The following works without any config in resources.groovy
class CalendarService {
#PostConstruct
private void init() {
User.findByEmail("foo#doo.com")
}
}

Resources