Grails String.encodeAsBase64() Fails in Spock Tests - unit-testing

This code works fine when I run it in Grails.
String getLoginToken() {
generatePassword()
passwordExpired = false
[email, password].join(',').encodeAsBase64()
}
However, this Spock test fails
def "test getLoginToken"() {
setup:
String email = "bacon#eggs.edu"
Person person = new Person(email: email)
when:
String token = person.getLoginToken()
then:
token.decodeBase64() == "$email,$person.password"
}
with the following exception
| Failure: test getLoginToken(com.campuscardtools.myphotoid.PersonSpec)
| groovy.lang.MissingMethodException: No signature of method: java.lang.String.encodeAsBase64() is applicable for argument types: () values: []
Possible solutions: decodeBase64()
at com.campuscardtools.myphotoid.Person$$EPFScS6i.getLoginToken(Person.groovy:140)
at com.campuscardtools.myphotoid.PersonSpec.test getLoginToken(PersonSpec.groovy:68)
My understanding is that Groovy provides the encodeAsBase64() on the String class (see: http://mrhaki.blogspot.com/2009/11/groovy-goodness-base64-encoding.html), so why doesn't this work in the unit test?

Rather than
"Blah".encodeAsBase64()
You need
"Blah".encodeBase64()
Without the 'As'

You could also include a mockCodec for the method you're using.
and: "add the Base64 codec"
mockCodec(org.codehaus.groovy.grails.plugins.codecs.Base64Codec)

This works, but I fells like a bad hack. Surely there must be cleaner solution:
def cleanup () {
String.metaClass = null
}
def "test getLoginToken"() {
setup:
String email = "bacon#eggs.edu"
Person person = new Person(email: email)
String encoded = null
and:
String.metaClass.encodeAsBase64 {
encoded = delegate
return delegate
}
when:
String token = person.getLoginToken()
then:
token == "$email,$person.password"
encoded == "$email,$person.password"
}

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(..).

Is it possible to mock a method in a Groovy class-under-test such that other methods within the class will use the mocked version?

For example:
class CutService {
String delegateToSelf(){
aMethod()
}
String aMethod(){
"real groovy value from CUT"
}
}
I've tried a variety of approaches, including:
#TestFor(CutService)
class CutServiceSpec extends Specification {
def expectedValue = "expected value"
void "test mocking CUT method using MockFor"() {
given:
MockFor mockCutService = new MockFor(CutService)
mockCutService.ignore.aMethod {expectedValue}
def cutServiceProxy = mockCutService.proxyDelegateInstance()
when:
String actualValue = null
mockCutService.use {
actualValue = cutServiceProxy.delegateToSelf()
}
then:
expectedValue == actualValue
}
}
Which gives:
| Failure: test mocking CUT method using MockFor(com...CutServiceSpec)
| junit.framework.AssertionFailedError: No more calls to 'delegateToSelf' expected at this point. End of demands.
at com...CutServiceSpec.test mocking CUT method using MockFor_closure4(CutServiceSpec.groovy:45)
at com...CutServiceSpec.test mocking CUT method using MockFor(CutServiceSpec.groovy:44)
Using metaClass appears to do what I want:
void "test mocking CUT method using metaClass"() {
given:
service.metaClass.aMethod = { expectedValue }
when:
String actualValue = service.delegateToSelf()
then:
expectedValue == actualValue
}
This test runs green.

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)

grails spock test mock CommonsMultipartFile

I've following old method written in code, which is for accessing request object in service class such as:
def someServiceMethod() {
....
def webUtils = WebUtils.retrieveGrailsWebRequest()
def request = webUtils.getCurrentRequest()
MultipartHttpServletRequest mpr = (MultipartHttpServletRequest) request
CommonsMultipartFile file = (CommonsMultipartFile) mpr.getFile("file")
....
}
This is my unit test code for serivce class.
#TestFor(SomeService)
class SomeServiceSpec extends Specification {
void "test someServiceMethod"() {
given:
MockMultipartHttpServletRequest request = new MockMultipartHttpServletRequest()
FileInputStream inFile = new FileInputStream("./test-data/Hiearchy-003.xlsx") //valid file path
def multipartFile = new GrailsMockMultipartFile('file', 'file.xls', 'multipart/form-data', inFile)
request.addFile(multipartFile)
GrailsWebRequest webRequest = new GrailsWebRequest(
request,
new MockHttpServletResponse(),
new MockServletContext()
)
request.setAttribute(GrailsApplicationAttributes.WEB_REQUEST,webRequest)
RequestContextHolder.setRequestAttributes(webRequest);
when:
def result = service.someServiceMethod()
then:
result != null
//some more assertions
//..
}
}
I'm stuck with following error.
| Failure: test someServiceMethod(SomeServiceSpec)
| org.codehaus.groovy.runtime.typehandling.GroovyCastException: Cannot cast object 'org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile#6ae8e5dd' with class 'org.codehaus.groovy.grails.plugins.testing.GrailsMockMultipartFile' to class 'org.springframework.web.multipart.commons.CommonsMultipartFile'
Anybody faced such issue before in grails unit test?
Instead of : GrailsMockMultipartFile,
use: org.springframework.mock.web.MockMultipartFile.
I just realised following line is just unnecessary if we use input stream direct it should not be problem hence solved my issue..
CommonsMultipartFile file = (CommonsMultipartFile) mpr.getFile("file")

Attributes are empty during unit test of a taglib in grails

I am trying to test my code in taglib (grails 2.0.1):
class ATagLib {
static namespace = "s"
def person = {attrs, body -> out << attrs.person;}
}
#TestFor(ATagLib)
class ATagLibTests {
#Test
void test() {
String p = 'Joe'
// None of these work for me.
assert applyTemplate('<s:person person="${p}"/>') == 'Joe'
assert applyTemplate('<s:person/>', [person:p]) == 'Joe'
}
}
The test always fails, because attrs.person is null. How do I properly set attributes?
This will work :
String p = 'Joe'
assert applyTemplate('<s:person person="${person}"/>', [person:p]) == 'Joe'
assertOutputEquals('Joe is cool !', '<s:person person="${person}"/>', [person:p], { it.toString() + " is cool !" } )
It calls the first signature of applyTemplate, which is :
String applyTemplate(String contents, Map model = [:])
Is the problem that you are using single quotes for your template text? Only GStrings can use the $ notation for inserting variables. Single quotes make it a regular Java String which won't substitute your value in.
Try this:
assert applyTemplate("<s:person person=\"${p}\"/>") == "Joe"