Scala - Mocking methods that return Value classes

959 views
Skip to first unread message

Taylor Smith

unread,
Oct 18, 2015, 10:41:16 AM10/18/15
to mockito
Hi all, 

When using Mockito with scala value classes there seems to be a limitation when trying to stub out methods that return value classes. 

import org.mockito.Matchers._
import org.mockito.Mockito._
import org.scalatest.FlatSpec
import org.scalatest.mock.MockitoSugar

case class ValueString(value: String) extends AnyVal

object ValueString {
 val sample
= ValueString("first")
}

class Example {
 
def calcValue(throwAwayVal: Int): ValueString = {
 
ValueString.sample
 
}
 
def calcValueWithException(throwAwayVal: Int): ValueString = {
 
throw new Exception("exception in calculating ValueString")
 
ValueString.sample
 
}
}

class ValueClassSpec extends FlatSpec with MockitoSugar {


 
"Mock return value" should "resolve mocking value classes with its primitive" in {
 val mockedClass
= mock[Example]
 val valClassInstance
= ValueString("second")

 
when(mockedClass.calcValue(anyInt())).thenReturn(valClassInstance)
 
assert(mockedClass.calcValue(2) == valClassInstance)
 
}

 
"Mocking return of value class with the primitive" should "return the primitive at runtime" in {
 val mockedClass
= mock[Example]
 val valClassInstance
: ValueString = ValueString("second")

 
// Works fine
 
when(mockedClass.calcValue(anyInt()).value).thenReturn(valClassInstance.value)
 
assert(mockedClass.calcValue(2) == valClassInstance)
 
}


 
"Mocking return of value class with the primitive" should "return the primitive at runtime despite exceptions in that method" in {
 val mockedClass
= mock[Example]
 val valClassInstance
: ValueString = ValueString("second")

 
// Common occurance when mocking class methods, because we have no intention of code in those methods scope to be executed
 
when(mockedClass.calcValueWithException(anyInt()).value).thenReturn(valClassInstance.value)
 
assert(mockedClass.calcValue(2) == valClassInstance)
 
}

}


Running this test produces error

[info] ValueClassSpec:
[info] Mock return value
[info] - should resolve mocking value classes with its primitive *** FAILED ***
[info] org.mockito.exceptions.misusing.WrongTypeOfReturnValue: ValueString cannot be returned by calcValue()
[info] calcValue() should return String
[info] ***
[info] If you're unsure why you're getting above error read on.
[info] Due to the nature of the syntax above problem might occur because:
[info] 1. This exception *might* occur in wrongly written multi-threaded tests.
[info] Please refer to Mockito FAQ on limitations of concurrency testing.
[info] 2. A spy is stubbed using when(spy.foo()).then() syntax. It is safer to stub spies -
[info] - with doReturn|Throw() family of methods. More in javadocs for Mockito.spy() method.
[info] at com.example.ValueClassSpec$anonfun$1.apply$mcV$sp(testthing.scala:32)
[info] at com.example.ValueClassSpec$anonfun$1.apply(testthing.scala:28)
[info] at com.example.ValueClassSpec$anonfun$1.apply(testthing.scala:28)
[info] at org.scalatest.Transformer$anonfun$apply$1.apply$mcV$sp(Transformer.scala:22)
[info] at org.scalatest.OutcomeOf$class.outcomeOf(OutcomeOf.scala:85)
[info] at org.scalatest.OutcomeOf$.outcomeOf(OutcomeOf.scala:104)
[info] at org.scalatest.Transformer.apply(Transformer.scala:22)
[info] at org.scalatest.Transformer.apply(Transformer.scala:20)
[info] at org.scalatest.FlatSpecLike$anon$1.apply(FlatSpecLike.scala:1647)
[info] at org.scalatest.Suite$class.withFixture(Suite.scala:1122)
[info] ...
[info] Mocking return of value class with the primitive
[info] - should return the primitive at runtime
[info] Mocking return of value class with the primitive
[info] - should return the primitive at runtime despite exceptions in that method *** FAILED ***
[info] ValueString(null) did not equal ValueString(second) (testthing.scala:52)
[info] ScalaCheck
[info] Passed: Total 0, Failed 0, Errors 0, Passed 0
[info] ScalaTest
[info] Run completed in 1 second, 210 milliseconds.
[info] Total number of tests run: 3
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 1, failed 2, canceled 0, ignored 0, pending 0
[info] *** 2 TESTS FAILED ***
[error] Failed: Total 3, Failed 2, Errors 0, Passed 1
[error] Failed tests:
[error] com.example.ValueClassSpec


Note the second and third test. This can work if you mock the value method, but it does not prevent execution of code within the scope of the mocked method. So if exceptions would be thrown by the mocked class method(which would commonly be the case) exception bubbles up to test scope and fails the test.

Has anyone managed to find a workaround or other solution to getting this functionality?

Bruno Bonanno

unread,
Nov 27, 2018, 7:31:51 PM11/27/18
to mockito
Maybe a bit late, but mockito-scala allows you to do this since version 1.0.3
Reply all
Reply to author
Forward
0 new messages