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

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.

Related

spring junit test data preparrer class access repositories trough field

I have simple class annotated with #Component and injected repositories like
#Component
class TestsDataPreparer(
private val carRepository: CarRepository
) {
fun withCar(builder: Car.() -> Unit = {}): Car {
return carRepository.save(
Car(
name = builder.name!!
)
)
}
}
which is clear..
But i wonder if it would be ok to do something like this, or if it is considered as anti-pattern.
#Component
class TestsDataPreparer(
val carRepository: CarRepository
) {
fun withCar(builder: Car.() -> Unit = {}): Car {
return carRepository.save(
Car(
name = builder.name!!
)
)
}
}
#Test
fun testCar() {
testsDataPreparer.withCar{this.name="Super-cool-car!"}
assertThat(testsDataPreparer.carRepository.findAll()).hasSize(1)
}
So the question is if it is okay to not inject repository in test class itself, but reuse it from TestsDataPreparer class
Yes, making an originally private field public just for testing can be considered an antipattern. Instead, you can create a CarRepository instance and then pass it to TestsDataPreparer when you create it. But for unit testing, you don't actually need that, you can use a mock and verify that the correct method was called (CarRepository.save).

Autowired not working in Scala Spring Boot project

Taking into account the following example where I'm trying to use the Sample configuration bean within SampleStarter to start the service with the bean properly filled. The .scala file has SampleStarter.scala as name, with Sample being defined within that exact same file.
#SpringBootApplication
#Service
object SampleStarter {
#(Autowired #setter)
var sample: Sample = _ // always null, #Autowired not working?
def getInstance() = this
def main(args: Array[String]): Unit = {
SpringApplication.run(classOf[Sample], args: _*)
sample.run()
}
}
#Configuration
#ConfigurationProperties("sample")
#EnableConfigurationProperties
class Sample {
#BeanProperty
var myProperty: String = _
def run(): Unit = { // bean config seems OK, when debugging with #PostConstruct the 'myProperty' value is filled properly
print(myProperty)
}
}
Whenever I hit sample.run() after SpringApplication.run(classOf[Sample], args: _*), sample property is always null. I reckon this has something to do with object in Scala since all their members are static AFAIK. I took this SO question How to use Spring Autowired (or manually wired) in Scala object? as inspiration but still can't make my code to work.
Is there something wrong the way I'm instantiating the classes or is it something related to Scala?
EDIT
Following #Rob's answer, this is what I did trying to replicate his solution.
#SpringBootApplication
#Service
object SampleStarter {
#(Autowired #setter)
var sample: Sample = _
def getInstance() = this
def main(args: Array[String]): Unit = {
SpringApplication.run(classOf[Sample], args: _*)
sample.run()
}
}
#Configuration // declares this class a source of beans
#ConfigurationProperties("sample") // picks up from various config locations
#EnableConfigurationProperties // not certain this is necessary
class AppConfiguration {
#BeanProperty
var myProperty: String = _
#Bean
// Error -> Parameter 0 of constructor in myproject.impl.Sample required a bean of type 'java.lang.String' that could not be found.
def sample: Sample = new Sample(myProperty)
}
class Sample(#BeanProperty var myProperty: String) {
def run(): Unit = {
print(myProperty)
}
}
#Configuration declares a source file that is capable of providing #Beans. This is not what you want. You want/need to have Sample as a POJO class (POSO?) and then have another class "AppConfiguration" (say) annotated with #Configuration that creates an #Bean of type Sample
My scala is very rusty so this may not compile at all but the structure should be roughly correct.
#Configuration // declares this class a source of beans
#ConfigurationProperties("sample") // picks up from various config locations
#EnableConfigurationProperties // not certain this is necessary
class AppConfiguration {
#Bean
def getSample(#BeanProperty myProperty: String): Sample = new Sample(myProperty)
}
class Sample {
var myProperty: String
def Sample(property : String) = {
this.myProperty = myProperty
}
def run(): Unit = {
print(myProperty)
}
}
Now you have a Sample class as an #Bean and it can be #Autowired in where ever necessary.
#SpringBootApplication
#Service
object SampleStarter {
// note its typically better to inject variables into a constructor
// rather than directly into fields as the behaviour is more predictable
#Autowired
var sample: Sample
def getInstance() = this // not required ??
def main(args: Array[String]): Unit = {
SpringApplication.run(classOf[Sample], args: _*)
sample.run()
}
}
FWIW, you can start the SpringBoot application independently and have the logic for #Service entirely separate. An #Service is another type of #Bean and is made available to the rest of the SpringBootApplication.

Spring framework and java like Object collectors In Scala

In Spring framework and Java world, there is an interesting object collector pattern that I use.
For example consider below -
public interface Calculator {
SomeOutput calculate(SomeInput input);
}
#Component
public class CalImpl1 implements Calculator {
public SomeOutput calculate(SomeInput input){
//some implementation
}
}
#Component
public class CalImpl2 implements Calculator {
public SomeOutput calculate(SomeInput input){
//some implementation
}
}
Now this can easily injected in another class using Spring DI
#Component
public class Main {
//This line collects all to implementors of this and set it here.
#Autowired
public List<Calculator> calculators;
//other methods
}
Now problem is I am not sure how same thing can be achieved in scala. I have done some search and found cake pattern (http://loicdescotte.github.io/posts/scala-di/) used in scala but that didn't seem to achieve same thing as object collectors like above. I also want to follow open close principle which I think gets violated in cake pattern but using object collectors I can easily achieve it.
is there a way achieve same object collectors like implementation in scala?
There are templates in lighbend activator that illustration using spring DI on Play, Akka and Scala applications. Please see this: https://www.lightbend.com/activator/templates#filter:spring
I haven't used Spring as DI, I usually use Guice (explicitly used because it's default on play framework 2) and Implicits parameters both as a compilation DI.
Sample:
class B
class X(x: Int)(implicit c: B)
//DI - mostly define in main method/application
implicit val c: B = new B
val x = new X(2)
Explicitly using java.util.List worked for me. This is not the prettiest solution but it shows that it basically works. Haven't tried that but implementing a corresponding PropertyEditor you could stick with the Scala types.
trait Calculator {
def calculate(input: SomeInput) : SomeOutput
}
#Component
class CalImpl1 extends Calculator {
override def calculate(input: SomeInput): SomeOutput = ...
}
#Component
class CalImpl2 extends Calculator {
override def calculate(input: SomeInput): SomeOutput = ...
}
#Component
class Main #Autowired()(calculators: java.util.List[Calculator]) {
// or inject field if constructor injection is not desired
// #Autowired
// var calculators: java.util.List[Calculator] = _
}
object Main {
def main(args: Array[String]) = {
val ctx = new AnnotationConfigApplicationContext("your package name here")
val main = ctx.getBean(classOf[Main])
// calculators should now be wired in the returned instance
}
}

How to wait for transactions to commit using Propagation REQUIRES_NEW

I want to integration test a service method that calls a method that uses #Transactional(propagation = Propagation.REQUIRES_NEW). However, assertions based on the inner (new) transaction fail.
class MyService {
#Transactional(propagation = Propagation.NESTED)
def method1() {
method2()
}
#Transactional(propagation = Propagation.REQUIRES_NEW)
def method2() {
// some code that will modify the DB
}
}
class MyServiceNonTransactionalIntegrationSpec extends IntegrationSpec {
static transactional = false
def myService = new MyService()
setup() {
// populate database here
}
cleanup() {
// teardown database here after tests complete
}
def method1() {
when: "we test the main method"
myService.method1()
then: "we should be able to see the result of method 1 and method 2"
// BUT: (!!!)
// assertions based on state of database fail, perhaps because new transaction
// wrapped around method 2 has not yet committed
}
}
How do I integration test method1()?
EDIT:
In an attempt to work around the proxy issue, I've tried the following, but still can't get it to work:
class MyService {
def myService2
#Transactional(propagation = Propagation.NESTED)
def method1() {
myService2.method2()
}
}
class MyService2 {
#Transactional(propagation = Propagation.REQUIRES_NEW)
def method2() {
// some code that will modify the DB
}
}
class MyServiceNonTransactionalIntegrationSpec extends IntegrationSpec {
static transactional = false
def myService = new MyService()
def myService2 = new MyService2()
setup() {
myService.myService2 = myService2
// populate database here
}
// rest as before
}
It's only a self-invoking problem if you're using org.springframework.transaction.annotation.Transactional - you should be using #grails.transaction.Transactional instead which has the same configuration options but uses AST transforms instead of runtime proxies to avoid the issue of not calling the proxied method. When using the Grails annotation each method is rewritten to simulate creating a proxy for each one, wrapping the code in a transaction template that's configured based on the annotation settings for that method (either explicit on the method, or inferred from a class-scope annotation).
But your tests are broken because you're using new to create the services. Always use dependency injection in integration tests so you get the configured Spring bean, not just a new uninitialized POGO. To do this, add the same property syntax you would outside of your tests:
def myService
def myService2
and remove unnecessary wiring code (e.g. myService.myService2 = myService2) that Spring does for you.
You've faced self-invoking. Look here: Spring - #Transactional - What happens in background? or Spring #Transactional Annotation : Self Invocation
Here is excerption from one of my classes:
#Service("authzService")
public class AuthorizationService implements IAuthorizationService {
#Resource(name="authzService")
private IAuthorizationService self;
I use this private member for self invoke methods with #Cached annotation.

Grails inject Service into Controller dependant on environment

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

Resources