Second Use of GrailsApplication Mock in Service Test Fails - unit-testing

I'm unit testing a Grails service and using Mocks to mock out calls to the
GrailsApplication class. I have one test that succeeds but when I try
subsequent tests they fail. I am using demand to mock the isDomainClass
method. I have tried copying and pasting the code from the test that
succeeds to the test method that fails but the second time the same code
runs it fails saying that no more calls to isDomainClass are expected. I'm
suspecting some leakage between the methods but I can't see where it is.
Things I've tried already:
Running the tests from the command line (I'm running the tests under SpringSource Tool Suite version 2.7.0.201105292341-M2.)
Moving the failing test to a different test class (the test that runs first succeeds)
Changing the number range in the demands clause to 1..5 (second test still fails)
Here is the relevant portions of my test case:
package simulation
import grails.test.*
import org.joda.time.*
import org.codehaus.groovy.grails.commons.GrailsApplication
class ObjectSerializationServiceTests extends GrailsUnitTestCase {
def objectSerializationService
protected void setUp() {
super.setUp()
objectSerializationService = new ObjectSerializationService()
}
protected void tearDown() {
super.tearDown()
objectSerializationService = null
}
void testDomainObjectSerialization() {
def otherControl = mockFor(GrailsApplication)
otherControl.demand.isDomainClass(1..1) {true}
otherControl.demand.getDomainClass(1..1) {className ->
assert className == "simulation.TestDomainClass"
TestDomainClass.class
}
objectSerializationService.grailsApplication = otherControl.createMock()
def now = new DateTime()
def testObject = new TestDomainClass([id:57, someOtherData:"Some Other
Data", theTime:now])
def testInstances = [testObject]
mockDomain(TestDomainClass, testInstances)
def serialized = objectSerializationService.serializeObject(testObject)
def deserialized =
objectSerializationService.deserializeObject(serialized)
assert deserialized == testObject
assert serialized.objectType == SerializedObject.ObjectType.DOMAIN
otherControl.verify()
}
void testSerializableSerialization() {
def otherControl = mockFor(GrailsApplication)
otherControl.demand.isDomainClass(1..1) {true}
otherControl.demand.getDomainClass(1..1) {className ->
assert className == "simulation.TestDomainClass"
TestDomainClass.class
}
objectSerializationService.grailsApplication = otherControl.createMock()
def now = new DateTime()
def testObject = new TestDomainClass([id:57, someOtherData:"Some Other
Data", theTime:now])
def testInstances = [testObject]
mockDomain(TestDomainClass, testInstances)
def serialized = objectSerializationService.serializeObject(testObject)
def deserialized =
objectSerializationService.deserializeObject(serialized)
assert deserialized == testObject
assert serialized.objectType == SerializedObject.ObjectType.DOMAIN
otherControl.verify()
}
}
And the output:
Testcase: testDomainObjectSerialization took 0.943 sec
Testcase: testSerializableSerialization took 0.072 sec
FAILED
junit.framework.AssertionFailedError: No more calls to 'isDomainClass'
expected at this point. End of demands.
at grails.test.MockClosureProxy.doBeforeCall(MockClosureProxy.java:66)
at grails.test.AbstractClosureProxy.call(AbstractClosureProxy.java:74)
at
simulation.ObjectSerializationService.serializeObject(ObjectSerializationService.groovy:20)
at simulation.ObjectSerializationService$serializeObject.call(Unknown
Source)
at
simulation.ObjectSerializationServiceTests.testSerializableSerialization(ObjectSerializationServiceTests.groovy:68)

I got a similar error trying to use mockFor on jms Message interface in multiple test cases.
I got around it by creating a custom interface that extends from the interface that needs to be mocked. You would use the custom interface to create the mock.
e.g.
private interface GrailsApplicationTest1 extends GrailsApplication(){}
testOne(){
def control = mockFor(GrailsApplicationTest1)
//...rest of code
}
private interface GrailsApplicationTest2 extends GrailsApplication(){}
testTwo(){
def control = mockFor(GrailsApplicationTest2)
//...rest of code
}
//add more private interfaces for additional test cases..
I'm not exactly sure why but I think the mockFor behaves differently between interfaces and non-interfaces. But that's just a wild guess.

Related

Spock interaction verification ignoring call to Mock method

The following Spock test is failing to not counting the call to the Mock method:
def setup() {
mojo = new PactCreateVersionTagMojo()
mojo.pactBrokerUrl = 'http://broker:1234'
mojo.pacticipant = 'test'
mojo.pacticipantVersion = '1234'
mojo.tag = 'testTag'
}
def 'calls pact broker client with mandatory arguments'() {
given:
mojo.brokerClient = Mock(PactBrokerClient)
when:
mojo.execute()
then:
notThrown(MojoExecutionException)
1 * mojo.brokerClient.createVersionTag(
'test', '1234', 'testTag')
}
You can find it here.
The SUT code, removing the argument validation code, is:
class PactCreateVersionTagMojo : PactBaseMojo() {
override fun execute() {
...
createVersionTag()
}
private fun createVersionTag() =
brokerClient!!.createVersionTag(pacticipant!!, pacticipantVersion.orEmpty(), tag.orEmpty())
You can find it here.
The error is as follows:
I have a very similar example on the same project that passes just fine:
def 'passes optional parameters to the pact broker client'() {
given:
mojo.latest = 'true'
mojo.to = 'prod'
mojo.brokerClient = Mock(PactBrokerClient)
when:
mojo.execute()
then:
notThrown(MojoExecutionException)
1 * mojo.brokerClient.canIDeploy('test', '1234',
new Latest.UseLatest(true), 'prod') >> new CanIDeployResult(true, '', '')
}
override fun execute() {
...
val result = brokerClient!!.canIDeploy(pacticipant!!, pacticipantVersion.orEmpty(), latest, to)
}
You can find the test above here and the SUT here.
I have investigated the call that happens during the test, and it seems as expected.
Additionally, I try to create the verification with wildcard argument constraints, but it still didn't work.
It seems to me that I have misconfigured my test, but I can't spot the difference between the test that passes and my failing test.
Your fun createVersionTag(..) looks like this:
fun createVersionTag(
pacticipant: String,
pacticipantVersion: String,
tag: String) {
}
I do not speak Kotlin, but I think you ought to open the method because otherwise it is final, which means it cannot be overridden by a subclass and thus not be mocked or stubbed by conventional means. This is also the difference to open fun canIDeploy(..).

How to test a grail service that has resultTransformer within withCriteria(Spock).?

In the below class, I just need RevShareFormula.withCriteria to return a result,
but getting the exception in resultTransformer() method.
Can anyone tell me how to Mock the below method so that i get some result from withCriteria
Here is the class:
class PartnerFinancialService {
def getPartnerPayeeRevenuShareDetails(long partnerPayeeId, def contextTypeCode) {
def partnerPayeesRevShareFormula = RevShareFormula.withCriteria {
resultTransformer(CriteriaSpecification.ALIAS_TO_ENTITY_MAP)
createAlias('partnerRevShareConfig', 'partnerRevShareConfig')
createAlias('pricingModel', 'pricingModel')
createAlias('partnerRevShareConfig.revshareCategory', 'revshareCategory')
and {
eq("revshareCategory.payeeProfileId", partnerPayeeId)
eq("revshareCategory.referenceContextTypeCode", contextTypeCode)
isNull("partnerRevShareConfig.revshareValidToDate")
}
projections {
property("id", "formulaId")
property("pricingModel.id", "pricingModelId")
property("pricingModel.pricingName", "pricingName")
property("pricingModel.pricingType", "pricingType")
..
..
}
}
}
Here is the test class
#TestFor(PartnerFinancialService)
#Mock(RevShareFormula)
class PartnerFinancialServiceSpec extends Specification {
void "test getPartnerPayeeRevShareDetails"() {
def partnerPayeeRevShare = new PartnerRevShareConfig()
partnerPayeeRevShare.id = 1
def revShareModel = new PricingModel();
revShareModel.id = 1
def partnerPayeeRevShareFormula = new RevShareFormula();
partnerPayeeRevShareFormula.id=5
partnerPayeeRevShareFormula.pricingModel = revShareModel
partnerPayeeRevShareFormula.partnerRevShareConfig = partnerPayeeRevShare
partnerPayeeRevShareFormula.revshareFormula = "revshare*10"
partnerPayeeRevShareFormula.revshareTierHighValue = 0
partnerPayeeRevShareFormula.revshareTierLowValue= 0
RevShareFormula.metaClass.static.withCriteria = {partnerPayeeRevShareFormula}
when:
def result = service.getPartnerPayeeRevenuShareDetails(1,"PKG")
then:
//assert result.pricingModel.id == 1
println "Succesfully Fetched from DB"
}
}
Getting the following exception.
<testcase classname="com.orbitz.dat.partners.PartnerFinancialServiceSpec" name="test getPartnerPayeeRevShareDetails" time="0.039">
<error message="No signature of method: com.orbitz.dat.partners.PartnerFinancialService.resultTransformer() is applicable for argument types: (org.hibernate.transform.AliasToEntityMapResultTransformer) values: [org.hibernate.transform.AliasToEntityMapResultTransformer#3632aa4]" type="groovy.lang.MissingMethodException">groovy.lang.MissingMethodException: No signature of method: com.orbitz.dat.partners.PartnerFinancialService.resultTransformer() is applicable for argument types: (org.hibernate.transform.AliasToEntityMapResultTransformer) values: [org.hibernate.transform.AliasToEntityMapResultTransformer#3632aa4]
at com.orbitz.dat.partners.PartnerFinancialService.$tt__getPartnerPayeeRevenuShareDetails_closure24(PartnerFinancialService.groovy:39)
at grails.gorm.CriteriaBuilder.invokeClosureNode(CriteriaBuilder.java:1093)
at grails.gorm.CriteriaBuilder.invokeMethod(CriteriaBuilder.java:314)
at org.grails.datastore.gorm.GormStaticApi.withCriteria_closure11(GormStaticApi.groovy:304)
at org.grails.datastore.mapping.core.DatastoreUtils.execute(DatastoreUtils.java:302)
at org.grails.datastore.gorm.AbstractDatastoreApi.execute(AbstractDatastoreApi.groovy:37)
at org.grails.datastore.gorm.GormStaticApi.withCriteria(GormStaticApi.groovy:303)
at com.orbitz.dat.partners.PartnerFinancialService.$tt__getPartnerPayeeRevenuShareDetails(PartnerFinancialService.groovy:38)
at com.orbitz.dat.partners.PartnerFinancialServiceSpec.test getPartnerPayeeRevShareDetails(PartnerFinancialServiceSpec.groovy:71)
Use an integration test. Never test ORM code with unit tests. I know it's slower and the experience is less enjoyable, but you are fooling yourself if you think that you are actually testing something related to database queries with this test. You are testing the testing framework of grails (the in-memory GORM implementation)

Failing Unit Test In Grails 1.3.7 Spock

I have this piece of code in a controller:
def update = {
Map model = [:]
model.foo = params.foo
model.bar = params.bar
def result = ""
MyObject obj = MyObject.findWhere(bar:bar, foo:foo)
MyObjectService.updateObj(model,obj)
result = true
render result as JSON
}
And this simple unit test:
def 'controller update'() {
given:
controller.params.foo = foo
controller.params.bar = bar
MyObject obj = new MyObject(bar:bar, foo:foo)
mockDomain(MyObject,[obj])
when:
controller.update()
then:
1 * MyObject.findWhere(bar:bar, foo:foo) >> obj
1 * MyObjectService.updateObj(model,obj)
and:
def model = JSON.parse(controller.response.contentAsString)
model == true
where:
foo = "0"
bar = "1"
}
Now this is failing by and it is telling me that, "not static method findWhere is applicable..." for those arguments. That "MyObject" is just an orm class, and when I run that application everything seems to be working fine, but the test is failing.
My logic is this:
I want to count how many times the findWhere and updateObj methods are call and I am also mocking their response. So findWhere will return the object I already mocked, and pass it on to the service.
Any ideas why this is failing ?
For mocking static methods you should use Spock's GroovyStub class which introduced in v0.7.

How to mock Shiro accessControl() method in grails unit test case

I am using shiro security in my grail application.
Grails version : 2.2.1
shiro : 1.2.0
I have a problem in writing grails unit test case for the controller with filter enabled. When the test case run without filters then it is working fine, if it runs withFilters then it is failing for accessControl() method not found in the controller. I dont know how to make Shiro's api to be visible while running the test case.I referred shiro unit test case link http://shiro.apache.org/testing.html but I couldn't get any info regarding accessControl().I have given sample code how my classes and test case looks like
MyController.groovy
def create() {
// getting request parameters and validation
String emailId = params.emailId
def ret = myService.createUser(emailId)
return ret
}
MyControllerFilters.groovy
def filters = {
loginCheck(controller: 'user') {
before = {
//do some business checks
// Access control by convention.
accessControl() // This is a dynamic method injected by ShiroGrailsPlugin to FilterConfig, but this is not visible during the test case.
}
}
MyControllerTests.groovy
#TestFor(MyController)
#Mock(MyControllerFilters)
class MyControllerTests {
#Before
void setup() {
// initializing some variables
}
void testCreateUserWithFilter() {
request.accessAllowed = true
withFilters(action:"create") {
controller.create()
}
assert response.message == "success"
}
}
Try to use:
ControllerOrService.metaClass.method = {
return "" //what you need to be returned
}
Add parameters to closure if method take parameters:
ControllerOrService.metaClass.method = { def a, def b ->
return a + b
}
Don't forget to use full name of method when you mock them in that way.

Grails metaclass modification not reliable within unit tests

In a grails 2 project I'm using groovy's metaclass programming to add some methods to my domain classes.
Everything is working fine at runtime and I can run my integration tests fine.
But for unit tests I have some issues.
I have created a test mixin that is in charge of initializing the metaclass programming part.
This mixin is not running reliably:
the methods added to the metaclass are not available, or they are available after a first call, or they are available only after a previous grails test-app unit: command has been called.
This is quite a problem for continuous build.
You should be able to reproduce this issue (at least with grails 2.0.4) by
0) create a new grails projects
1) add a domain object
create-domain-class playground.Data
2) add this class to your src/groovy/playground dir
package playground
import grails.test.mixin.domain.DomainClassUnitTestMixin
import grails.test.mixin.support.GrailsUnitTestMixin
import org.codehaus.groovy.grails.commons.GrailsApplication
import org.codehaus.groovy.grails.commons.GrailsDomainClass
import org.junit.Before
class EnhanceDomainTestMixin {
boolean enhancerMethodCalled = false;
GrailsApplication application
MetaMethod mockDomainMethod
//replace the mockDomain Method from DomainClassUnitTestMixin with this closure
def enhancedMockDomain = { Class cl, List list ->
def enhanced =cl.metaClass.getMetaMethod("isEnhanced")
try {
//run the mockDomain method to have the mocked domain class registered in the grails application
mockDomainMethod.invoke(delegate, cl, list)
}
finally {
//enhance the grails domain with a new method
def domain = application.getDomainClass(cl.name) as GrailsDomainClass
domain.metaClass.isEnhanced = { return true; }
assert domain.newInstance().isEnhanced();
}
}
#Before void runDomainEnhancer() {
enhancerMethodCalled = true;
//GrailsUnitTestMixin.initGrailsApplication() should have already been called. (at least this was not an issue here)
application = GrailsUnitTestMixin.grailsApplication
//pick the mockDomain method
mockDomainMethod = DomainClassUnitTestMixin.metaClass.pickMethod("mockDomain", Class, List)
//if the picked mockDomain has never been enhanced, wrap it.
if(mockDomainMethod != enhancedMockDomain) {
DomainClassUnitTestMixin.metaClass.mockDomain = enhancedMockDomain
}
}
}
3) Add this small utils class (in test/unit/playground)
package playground
class TestSetup {
static Data d1
static void setup() {
d1 = new Data()
assert d1.isEnhanced()
}
}
4) Add these tests into the unit test already created by grails DataTests
package playground
import grails.test.mixin.*
#TestFor(Data)
#TestMixin(EnhanceDomainTestMixin)
class DataTests {
void testIsEnhancedLocal() {
assert enhancerMethodCalled
Data d = new Data()
assert d.isEnhanced()
}
void testIsEnhancedLocalSecondTime() {
assert enhancerMethodCalled
Data d = new Data()
assert d.isEnhanced()
}
void testIsEnhancedGlobalFirstTime() {
assert enhancerMethodCalled
TestSetup.setup()
assert TestSetup.d1 != null
}
void testIsEnhancedGlobalSecondTime() {
assert enhancerMethodCalled
TestSetup.setup()
assert TestSetup.d1 != null
}
}
Now run this command:
grails test-app unit:
you should have something like this output:
| Completed 4 unit tests, 4 failed in 1651ms
| Tests FAILED - view reports in target\test-reports
Now run the this command again (sometime one more is needed):
grails test-app unit: playground.DataTests
testMixin> grails test-app unit: playground.DataTests
| Completed 4 unit tests, 0 failed in 1384ms
| Tests PASSED - view reports in target\test-reports
So does anyone has a clue of why the metaClass modification is not reliable while running unit tests ? And how to workaround this issue ?
I had to use grailsApplication config in my domain class method. I ran into the same problem. Try using Holders.config instead of grailsApplication.config. It worked for me.