grails unit testing with multiple datasource - unit-testing

I am trying to write unit test case for grails controller which has following structure:
class MyController{
def save(){
def myDomain = new MyDomain(params)
business validation 1
business validation 2
myDomain.writedatasource.save()
business validation 3
business validation 4
}
}
Since Unit test doesn't load Datasource.groovy the writedatasource isn't available during unit testing so the test cases for "business validation 3" and "business validation 4" fail as I get
groovy.lang.MissingPropertyException: No such property: writedatasource for class: MyDomain
How can I modify my test case to test validation scenarios 3 and 4?
Test case is simple and looks like follows:
void testSave(){
...setup...
controller.save()
assert conditions
....
}

Not sure if that could make the trick, but you can try:
def 'the controller call the save method in writedatasource'() {
given:
def calls = 0
and:
def myDomainInstance = new MyDomain()
and:
MyDomain.metaClass.getWritedatasource = { new Object() }
and:
Object.metaClass.save = { Map attrs ->
calls++
}
when:
controller.save()
then:
calls == 1
}
But the only thing are you doing is testing that the save is called under writedatasource, so it would be better to have also an integration test. If that makes the trick, please answer as well at http://grails.1312388.n4.nabble.com/Mocking-in-a-unit-test-a-domain-object-multiple-datasources-td4646054.html as they seem to have the same problem.

Addressing original question:
I ran into this and would have had to mock many, many more methods than just 'save' on multiple domains. So instead, I overrode the getter of my domains to simply return the invoking domain instance:
def setup() {
[MyDomain1, MyDomain2].each { Class clazz ->
mockDomain(clazz)
clazz.metaClass.getWritedatasource = {
return delegate
}
clazz.metaClass.'static'.getWritedatasource = {
return delegate
}
}
}
This also saves me from including #DirtiesRuntime since I'm not updating the metaClass of anything I'd want to clean.
Most importantly, whatever calls the datasource, be it the domain class or the instance, it should be decorated with GORM fanciness from mockDomain, meaning I don't have to mock any of the GORM methods.
What if you want dynamic datasources?
In my particular case, datasources are configurable and may change depending on environment. If you're in a similar situation, you can configure this in your domain mapping:
static mapping = {
datasources Holders.grailsApplication?.config.dynamic?.datasources
...
}
where dynamic.datasources is an array of datasource names. Then, in the test setup:
def setup() {
grailsApplication.config.dynamic.datasources = ['foo', 'bar']
[MyDomain1, MyDomain2].each { Class clazz ->
mockDomain(clazz)
grailsApplication.config.dynamic.datasources.each{
clazz.metaClass."get${it.capitalize()}" = {
return delegate
}
clazz.metaClass.'static'."get${it.capitalize()}" = {
return delegate
}
}
}
}

Related

How can I setup test data for functional testing in Grails?

So we have a restful service that we want to test using a restclient in grails.
The test code should go something like this...
class MyControllerSpec extends Specification {
def setup() {
this.dbEntity = new DbEntity("someid123").save();
}
void "Test entity GET"{
given:
RestBuilder rest = new RestBuilder()
when: "The DB entity service is hit"
RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$id");
then: "A 200 error is sent"
restResponse.status == 200
}
The problem I am having is the setup method blows up on .save() because there is not hibernate session. How can I manipulate my database before running a test?
You can define a method named like "setupData", and call it in the "given" block of "Test entity GET" testcase.
def setupData() { this.dbEntity = new DbEntity("someid123").save(); }
If you need to load some data before each funcional test, you can create a helper class, with #Shared variables or methods or both. Even you could override the setup, setupSpec methods in that class.
Your first class does not extends Specification now, DataLoader class (helper class) instead.
class MyControllerSpec extends DataLoader {
void setup(){
createEntity()
}
void "Test entity GET"{
given:
RestBuilder rest = new RestBuilder()
when: "The DB entity service is hit"
RestResponse restResponse = rest.post("http://localhost:8080/api/someentity/$dbEntity.id");
then: "A 200 error is sent"
restResponse.status == 200
}
}
And your helper class is the one which extends Specification, with its methods and #Shared variables.
import spock.lang.Shared
class DataLoader extends Specification {
#Shared DbEntity dbEntity
void createEntity(){
dbEntity = new DbEntity("someid123").save();
}
}
When extending GebSpec in Grails 2.5.6, none of the other answers helped: I would still get
Method on class [...] was used outside of a Grails application
on the save() call.
Adding #TestFor(DbEntity) to the test class helped.
NB: While that annotation breaks integration tests, it seems to be necessary here. Not sure why that is.
You probably want to use the remote-control plugin. In Grails 2.x, add this to your BuildConfig.groovy:
repositories {
...
mavenRepo "http://dl.bintray.com/alkemist/maven/"
}
plugins {
...
test ":remote-control:2.0"
}
After refreshing dependencies and potentially adjusting some settings (see e.g. here and here), you can use it like so in tests:
// <project>/test/functional/<package>/MyControllerSpec.groovy
class MyControllerSpec extends GebSpec {
RemoteControl remote
DbEntity dbEntity
def setup() {
this.remote = new RemoteControl()
this.dbEntity = remote {
new DbEntity("someid123").save()
}
}
def cleanup() {
remote {
DbEntity.findAll().each { dbe ->
println("Deleting $dbe")
dbe.delete()
}
}
}
Note:
You can invoke remote in given/setup and when blocks as well.
Sometimes, it seems to be necessary to wrap core in remote { ... } in a DbEntity.withTransaction { ... }. Maybe that's obvious for the more intitiated; I stumbled over that.
If you want to return a DbEntity from remote it must be serializable.

mocking a function call

Using Spock framework for java unit testing.
When unit testing a method method1() and method1 is calling a method method2(),In method2() having a code statement as below :
Config config = new Config();
TimeZone tz=TimeZone.getTimeZone(config.getProps().getProperty(Constants.SERVER_TIMEZONE));
The call config.getProps().getProperty(Constants.SERVER_TIMEZONE)
returns America/Cambridge_Bay
In getProps method the property files is fetched from weblogic domain and it will not be available in spcok, its taking path as null.
Please suggest how can this function call be mocked in spock.
We can use meta class injection to mock response method2 in unit testing given block. Here ClassName is the class to which method2 belongs to.
ClassName.metaClass.method2 = { inputParameters ->
return "America/Cambridge_Bay"
}
Also it is advisable to use #ConfineMetaClass([ClassName]) annotation on the unit test to confine the meta class injection changes to your test case.
Lets start with an example which simulates your situation:
class Config {
Properties getProps() {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'America/Cambridge_Bay')
props
}
}
class Constants {
static String SERVER_TIMEZONE = 'TIMEZONE'
}
Config config = new Config()
def timeZoneID = config.getProps().getProperty(Constants.SERVER_TIMEZONE)
def tz = TimeZone.getTimeZone(timeZoneID)
assert tz.ID == 'America/Cambridge_Bay'
Since method2() doesn't get a Config instance injected into it, mocks are out of the question. So we'll use Groovy's metaClass, at the class level (since instance level is out of the question too, for the same reason). You can override Config.getProps() like this:
Config.metaClass.getProps {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'Etc/UTC')
props
}
So you can write your Spock test roughly like this:
// import Constants
// import Config class
class FooSpec extends Specification {
#ConfineMetaClassChanges
def "test stuff"() {
when:
Config.metaClass.getProps {
def props = new Properties()
props.setProperty(Constants.SERVER_TIMEZONE, 'America/Cambridge_Bay')
props
}
// Do more stuff
then:
// Check results
}
}
PS
If you can modify method2() to have Config injected, that would be preferable since then you can use Groovy's MockFor.

Understanding Grails mockFor demand

I'm trying to write a unit test for my filters, and I'm struggling to understand the demand for my mocked object. Here is a simple failing test:
void "test my sanity"() {
setup:
def vendorPayment = mockFor(Payment)
vendorPayment.demand.buyerId { -> 123}
def vp = vendorPayment.createMock()
//vp.buyerId=123
println "buyer id: ${vp.buyerId}"
when:
def a = "testing"
then:
vp.buyerId == 123
}
I wanted to mock the getter for buyerId. Using demand doesn't work, but if I create the mock and then set the buyer id (the commented line), the test will pass. Does demand not work with getters? Is it because the getter is implicitly/dynamically created?
Method getBuyerId has to be mocked. Groovy adds the accessor methods for you in compile time, so method on demand has to be mocked. Take this simple case:
class Payment {
Integer buyerId
}
Getter/Setter for Payment.groovy will be added when the class is converted to bytecode after compile. Corresponding test would look like:
void "test my power"() {
setup:
def vendorPayment = mockFor(Payment)
vendorPayment.demand.getBuyerId(1..2) { -> 123}
def vp = vendorPayment.createMock()
println "buyer id: ${vp.buyerId}"
expect:
vp.buyerId == 123
//This would fail for < 2.3.* because of this bug which is fixed in 2.4
//http://jira.grails.org/browse/GRAILS-11075
vendorPayment.verify() //null
}
Note the changes that was made:
getBuyerId method is mocked instead of the field buyerId
test demands that getBuyerId will be called 1 to 2 times (first while printing, second in then block). By default if nothing is specified, it assumes the method will be called once, which would fail in this case as getBuyerId is invoked twice.
We can also verify that the mock control did its job after the test is done

Mocking static get gorm method in Grails unit test

I'm using Grails 2.3.7. I have a simple Person domain object:
class Person {
String name
static constraints = {}
}
And controller:
#Transactional(readOnly = true)
class PersonController {
def index() {
render view:'index', model:[personList:Person.list()]
}
def show(Long id) {
def person = Person.get(id)
render view:'show', model:[person:person]
}
...
}
I'm trying to write a unit test for the controller to exercise the show method, but I am not sure how I need to configure the test to ensure that the static call Person.get(id) returns a value.
Here's my (failing) attempt:
import grails.test.mixin.*
import spock.lang.*
#TestFor(PersonController)
#Mock(Person)
class PersonControllerSpec extends Specification {
void "Test show action loads Person by id and includes that person in the model rendered"() {
setup:
def personMockControl = mockFor(Person)
personMockControl.demand.static.get() { int id -> new Person(name:"John") }
when:"A valid person id passed to the show action"
controller.show(123)
then:"A model is populated containing the person domain instance loaded by that unique id"
model.person != null
model.person.name == "John"
}
}
This test fails because the condition model.person != null fails. How do I rewrite this test in order to make it pass?
EDIT
In this case I can side-step the static method call by reworking the test thusly:
void "Test show action loads Person by id and includes that person in the model rendered"() {
setup:
def p = new Person(name:"John").save()
when:"A valid person id passed to the show action"
controller.show(p.id)
then:"A model is populated containing the person domain instance loaded by that unique id"
model.person != null
model.person.id == p.id
model.person.name == "John"
}
However, I'd really like to understand how to correctly mock the Person's static get method.
EDIT 2
Here's another situation to demonstrate my perceived need to mock the get method. Given this filter code:
def fitlers = {
buyFilter(controller:"paypal", action:"buy") {
after = {
new VendorPayment(payment:request.payment, vendor: Vendor.get(params.buyerId)).save()
}
}
}
I'm trying to test that this filter works as expected using the following test:
void "test the buyFilter to ensure it creates a VendorPayment when the PayPal plugin controller is called" () {
setup:
// how do I mock the Vendor.get(params.buyerId)
// to return a vendor in order to save a new VendorPayment
when:
withFilters(action:"buy") {
controller.buy()
}
then:
VendorPayment.count() == 1
}
Like dmahaptro mentioned, you do not need to mock your person. The preferred/proper way of grabbing an object in a test via .get() is the way you have it--you create the domain instance, and pass its id to the controller action for consumption.
However, if you need to mock a static method like this there are two approaches:
1) Use the mockFor method provided by GrailsUnitTestMixin and then specify the static method like so:
GrailsMock mockPerson = mockFor(Person)
mockPerson.demand.static.get() { Long id -> new Person(name:"John") }
Note that in your case, the mock's static get method did not contain the correct parameter type (int was used instead of Long) so this method was not being invoked.
2) Modify the class' metaClass. Changing the metaClass is highly discouraged (especially when the #Mock annotation already sets everything up for you), and can lead to test leakage (i.e., other tests will not work properly after you've changed the metaClass, unless you restore the original metaclass after the test is done).
That said, for the sake of familiarity, the way you would mock the .get() method is via:
Person.metaClass.static.get = { Long id -> return personWithId }
Again, this is considered bad practice and should be avoided, but there you have it.

Cant use grailsApplication.getMetadata.get(" ") while performing unit test for controller in grails

In my grails application, in the controller, I use following kind of a thing :
class SampleController {
def action1 = {
def abc = grailsApplication.getMetadata().get("xyz")
render abc.toString()
}
}
While running the app, it correctly reads the property "xyz" from application.properties and works fine. But when I write a unit test case for the above controller as follows :
class SampleControllerTests extends ControllerUnitTestCase {
SampleController controller
protected void setUp() {
super.setUp()
controller = new SampleController()
mockController(SampleController)
mockLogging(SampleController)
}
void testAction1() {
controller.action1()
assertEquals "abc", controller.response.contentAsString
}
}
But when I do "grails test-app", I expect that it will pick up the property "xyz" from application.properties and will return as expected. But it gives error as "No such property : grailsApplication".
I understand, I guess I need to mock grailsApplication object and I tried many of the options also But all those didn't work.
I am new to Grails.
mockController will not mock the GrailsApplication, you will need to do it yourself.
The fastest solution would be something like:
protected void setUp() {
super.setUp()
mockLogging(DummyController)
GrailsApplication grailsApplication = new DefaultGrailsApplication()
controller.metaClass.getGrailsApplication = { -> grailsApplication }
}
This solution is not perfect - it will create a new DefaultGrailsApplication during each setup and mockController also creates some additional instances of DefaultGrailsApplication.
Note that you do not need to call mockController by yourself it will be done by the ControllerUnitTestCase for you.