Groovy HTTPBuilder Mocking the Client - unit-testing

This question is closely related to this question. The difference is that I'd like to follow the recommended approach of mocking the client. So, I have the following HTTPBuilder defined:
protected readUrl() {
def http = new HTTPBuilder("http://example.com")
def status = http.request(Method.GET, ContentType.JSON) {req ->
response.success = {resp, json ->
result = json.toString()
new Success<String>(result)
}
response.'401' = {resp ->
final String errMsg = "Not Authorized"
new Failed(Failable.Fail.ACCESS_DENIED, errMsg)
}
response.failure = {resp ->
final String errMsg = "General failure ${resp.statusLine}"
new Failed(Failable.Fail.UNKNOWN, errMsg)
}
}
}
What I'd like to do is find a way to unit test this code block. I wanted to mock the response so I could specifically set the response codes, if possible. Could someone please show me a way to do this?

This is my prefered solution:
class MockHTTPBuilder{
MockHTTPBuilder(string){}
MockHTTPBuilder(){}
def pleaseFail = false
def mockData = []
def request(a, b, c){
if(pleaseFail) [status:'500',data: mockData ?: "It failed :("]
else [status:'200',data: mockData ?: "Yay :)"]
}
}
Here's some sample usages: http://groovyconsole.appspot.com/script/760001
Alternatively, you can metaprogram the actual httpClient instance and make it behave as expected(forcebly failing or passing during test-time) but that's a little bit more complicated.

Related

how to validate reactor context value in Groovy test in spring rest call

please help on how to get reactor context value in Groovy test
private Mono<PersonDetail> getMemberDetailsWithName(String studNumber, PersonDetail detail) {
Set<StudError> errors = new HashSet<>();
return coreCustomerIndividualNameClient.getStudName(studNumber)
.map(nameResponse -> {
detail.setName(mapper.map(nameResponse));
return detail; })
.onErrorResume(e -> {
errors.addAll(e);
return Mono.just(detail);
})
.handle((studDetail, sink) -> {
StudContext studAggCtx = sink.currentContext().get(StudContext.CONTEXT_KEY);
studAggCtx.getErrors().addAll(errors);
sink.next(studDetail);
});
}
I am mocking,
.getStudName(studNumber) return Error.
I need to check whether the context got added with Error, how we can validate this in StepVerifier.create
the context created in the below way through reactor.util.context
.subscriberContext(Context.of(StudContext.CONTEXT_KEY,
new StudContext(headers, timeoutMillis, false)))
.collectList().block();
You can use the method expectAccessibleContext to gain access to the ContextExpectations methods. You can then use these methods to assert the state of the Context.
Example
Mono<Integer> mono = Mono.just(1)
.subscriberContext(Context.of("key", "value"));
StepVerifier.create(mono)
.expectAccessibleContext()
.contains("key", "value")
.then()
.expectNext(1)
.verifyComplete();
expectAccessibleContext docs

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

Why some regular expressions are not working with java.util.regex.Pattern

Currently I am working on one of the BLE communication-related app, Where BLE device sending data in JSON format. I have one requirement to make sure that received data should be in JSON format before passing to the caller method.
So, I have created one JSON Validator which is going to validate received response should have expected field name and JSON Object and Array symbols. Here is JSONValidator Kotlin code which is testing JSON Object and Array symbol in response.
class JSONValidator: StringValidator() {
private val jsonArray = "(^\\[|]\$)"
private val jsonObject = "([{}])"
private val jsonArrayAndObject = "(^\\[\\{|}]\$)"
override fun isStringValid(s: String?): Boolean {
return if (s == null || s.isEmpty()) {
false
} else {
doesPacketContainJson(s)
}
}
private fun doesPacketContainJson(s: String): Boolean {
return Regex(jsonObject).containsMatchIn(s) ||
Regex(jsonArray).containsMatchIn(s) ||
Regex(jsonArrayAndObject).containsMatchIn(s)
}
}
JSONValidator Test Class
class JSONValidatorTest {
private val packetValidator: StringValidator = JSONValidator()
// Other Test cases
#Test
fun `validate contains json`() {
val partialJson1 = "{"
val partialJson2 = "}"
val partialJson3 = "[{"
val partialJson4 = "]}"
val partialJson5 = "]"
//Issue: These test cases always failed
assert(packetValidator.isStringValid(partialJson1))
assert(packetValidator.isStringValid(partialJson2))
assert(packetValidator.isStringValid(partialJson3))
assert(packetValidator.isStringValid(partialJson4))
assert(packetValidator.isStringValid(partialJson5))
}
}
I have cross verified Regular expression on below sites and It's working fine over there. I hope I am doing things right. :
https://regex101.com/
https://www.freeformatter.com/java-regex-tester.html
I did google but unable to find any help around my use-case. Can anyone have any experience or idea around this issue? Thanks in advance.

Grails String.encodeAsBase64() Fails in Spock Tests

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

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)