Pages

Spock - call mocked method multiple times and return different results for same input

Spock - return different mock result for same input

In unit testing, we create and use mock objects for any complex/real object that's impractical or impossible to incorporate into a unit test. Generally any component that's outside of the scope of unit test are mocked. Mocking frameworks like JMock, EasyMock, Mockito provide an easy way to describe the expected behavior of a component without writing the full implementation of the object being mocked.

In Groovy world, the Spock testing framework includes powerful mocking capabilities without requiring additional mocking libraries.

In this article, I am going to describe how we can create mock objects that can be called multiple times and and each time they return multiple values.

First, let's see how we can return Fixed Values from a mocked method: for this, we use the right-shift (>>) operator to return a fixed value:
//the input parameter is _(any) and it will return "ok" everytime
mockObj.method(_) >> "ok"
To return different values for different invocation
//return 'ok' for param1 and 'not-ok' for param2
mockObj.method("param1") >> "ok"
mockObj.method("param2") >> "not-ok"

Finally, to return different values for same parameter: for this, we use triple-right shift (>>>) operator.
mockObj.method("param") >>> ["", "ok", "not-ok"]

It will return empty value for first invocation, "ok" for second and "not-ok" for third and rest of the invocation.


Let's see in action

build.gradle:

 plugins {  
   id 'groovy'  
 }  
 repositories {  
   mavenCentral()  
   jcenter()  
 }  
 dependencies {  
   implementation 'org.codehaus.groovy:groovy:2.5.13'  
   testImplementation platform('org.spockframework:spock-bom:1.3-groovy-2.5')  
   testImplementation 'org.spockframework:spock-core' //version provided by bom  
   testImplementation 'org.junit.jupiter:junit-jupiter-params:5.6.2'  
   testImplementation "org.junit.jupiter:junit-jupiter-api:5.6.2"  
   testRuntimeOnly "org.junit.vintage:junit-vintage-engine:5.6.2"  
 }  
 test {  
   useJUnitPlatform()  
 }

MemberService/RegCodeService

 package mockex  
interface RegCodeService { String getRegCode(String name); void createCode(String name) }
class MemberService { RegCodeService regCodeService
String getRegistrationCode(Member m) { String regCode = regCodeService.getRegCode(m.name) if (!regCode) { regCodeService.createCode(m.name) } return regCodeService.getRegCode(m.name) } }
class Member { String name }

MemberServiceSpec

 package mockex  
 import spock.lang.Specification  
class MemberServiceSpec extends Specification {
MemberService memberService RegCodeService regCodeService
def setup() { regCodeService = Mock(RegCodeService) memberService = new MemberService(regCodeService: regCodeService) }
def 'regCode test'() { given: Member m = new Member(name: "Bob")
when: String regCode = memberService.getRegistrationCode(m)
then: regCodeService.getRegCode(m.name) >>> ['', 'REG_CODE_001'] regCode == 'REG_CODE_001' } }


Here we are mocking the RegCodeService.getRegCode to return empty at first and then 'REG_CODE_001' on the same parameter.


Hope this helps!

No comments:

Post a Comment

Your Comment and Question will help to make this blog better...