I have an abstract class that looks like that:
abstract class ReadOnlyJsonFormat[T] extends RootJsonFormat[T] {
final def write(obj: T): JsValue = throw DeserializationException("Unsupported operation")
}
The idea it simple: my subclasses implement a read-only JSON, I don't care about writing any object to JSON.
Now I'd like to use Mockito to test such class through a mock, where I can call the implemented method, and the following works:
"My nice test" should "raise an exception" in {
val readOnlyJsonFormat = mock[ReadOnlyJsonFormat[Int]]
intercept[DeserializationException] {when(readOnlyJsonFormat.write(1)).thenCallRealMethod()}
val exc = intercept[DeserializationException] {
readOnlyJsonFormat.write(1)
}
exc.getMessage must be ("Unsupported operation")
}
But since my method throws an exception when .write(), I'm forced to intercept such exception when defining the behavior of the mock, something that in Java was not necessary. Am I using Mockito in the wrong way? I tried using ScalaMock but I haven't found a way to call the real method on .
Related
I have a trait with functions implemented in it. I want to mock the methods of trait and for a method, I want to use thenCallRealMethod. I am using Mockito Framework in Scala. But when I try to use thenCallRealMethod for a method, then I get the following error :
Cannot call abstract real method on java object!
Calling real methods is only possible when mocking non abstract method.
//correct example:
when(mockOfConcreteClass.nonAbstractMethod()).thenCallRealMethod();
org.mockito.exceptions.base.MockitoException:
Here is my Code :
trait X{
def solve() : String = "solve"
def solve2() : String = "solve2"
}
class XTest extends FlatSpec with Matchers with MockitoSugar{
"test" can "test methods in trait" in{
val mockedX = mock[X]
when(mockedX.solve()) thenCallRealMethod()//this line throws the error
}
}
This code throws the error metioned. One approach is using a class which can extend the trait, but I don't want to extend the trait and looking for another approach.
(I encountered this issue while upgrading scala 2.13 code from JDK 11 to JDK 17)
As you say in your comment you're actually wanting a base implementation in solve that calls another extended method:
trait X{
def solve() : String = "solution: " + solve2()
def solve2() : String
}
(please update your question with some code similar to your actual problem...)
As #Dima said, this violates SRP. So, make a method with the correct responsibility
object X {
def solve(x: X) : String = "solution: " + x.solve2()
}
and test this. Since you probably want to have fluent calls (and method discoverability), delegate from the trait:
trait X{
def solve() : String = X.solve(this)
def solve2() : String
}
For me, this falls into the "too simple to test" category and allows you to keep your other code as-is, while keeping logic separate for testing etc.
I'm trying to test an Object.method which contains some nested methods from a Trait apart of some calculations. These nested methods have to be mocked (they access to a DB so I want to mock their responses).
When I call the real Object.method, it should skip the nested methods call and retrieve what I want. I've tried mocking them but test is still calling them.
Here's my example source code:
trait MyTrait {
def myMethodToMock(a: String): String
}
object MyObject extends MyTrait {
def myParentMethod(a:String) = {
val b = myMethodToMock(a)
val c = a + b
c
}
}
Then in my test:
val myTraitMock = mock[MyTrait]
when(myTraitMock.myMethodToMock(a)).thenReturn(b)
//Then I call the parent method:
assert(MyObject.myParentMethod(a) equals c)
It throws a NullPointerException as it's still accessing to myMethodToMock
Your code does not compile, so I am going to guess some things of what you are actually trying to do here ...
You are stubbing a method on a mock, and then calling it on a completely unrelated instance. No wonder it does not work.
A good rule of thumb (and the best practice) is to never mock classes you are actually testing. Split everything you want to mock and test separately into a separate class. This is also known as single responsibility principle (each component should be responsible for a single thing).
trait MyTrait {
def myMethodToMock(a: String): String
}
object MyTrait extends MyTrait {
def myMethodtoMock(a: String) = ???
}
class MyObject(helper: MyTrait = MyTrait) {
def myParentMethod(a: String) = a + helper.myMethodToMock(a)
}
object MyObject extends MyObject()
Now, you can write your test like this:
val myTraitMock = mock[MyTrait]
when(myTraitMock.myMethodToMock(any)).thenReturn("b")
new MyObject(myTraitMock).myParentMethod("a") shouldBe "ab"
verify(myTraitMock).myMethodToMock("a")
The main difference here is that you are passing your mock into the object's constructor, so that when it calls the method, it will be the one you stubbed, not the implementation provided by the default class.
You should use composition rather than inheritance, so you can inject an instance of MyTrait that can be a mock or the real one
I'm trying to mock a method that returns an instance of a value class (extends AnyVal)
I'm getting some weird error message, which I understand (because of value class erasure) but I'm surprised Mockito doesn't cope with that.
My class:
case class MyValueClass(value: String) extends AnyVal
The function I want to mock:
trait ToMock {
def something(someParams: String): MyValueClass
}
And the mock:
val theMock = mock[ToMock]
val returned = MyValueClass("test")
when(theMock.something("test")).thenReturn(returned)
This code generates the following error:
MyValueClass cannot be returned by something()
something() should return String
But of course, if I make it return a String, it doesn't compile anymore...
If I remove extends AnyVal, of course it works fine.
OK, I found an answer that works.
I need to use the older mockito style of doReturn
doReturn(returned.value).when(theMock).something("test")
Because it's not type-safe, it works.
Not fully satisfactory though, as I give up type safety.
trait UserRepository {
def findByFirstName(firstName: String): Seq[User]
}
trait UserBusinessDelegate extends UserRepository {
abstract override def findByFirstName(firstName: String) = {
super.findByFirstName(firstName)
}
}
class MockUserRepository extends UserRepository {
override def findByFirstName(firstName: String) = {
// whatever
}
}
val userRepository = new MockUserRepository with UserBusinessDelegate
userRepository.findByFirstName("John") // OK
However, if I change UserBusinessDelegate as follows:
trait UserBusinessDelegate {
self: UserRepository =>
override def findByFirstName(firstName: String): Seq[User] = {
self.findByFirstName(firstName) // requires explicit return type, thinks this is a recursive call
}
}
val userRepository = new MockUserRepository with UserBusinessDelegate
userRepository.findByFirstName("John") // StackOverflow!!!
I understand stackable pattern and hence how the first case works. My question is why the 2nd doesn't.
In the second snippet you have a recursive call without an exit condition:
override def findByFirstName(firstName: String): Seq[User] = {
self.findByFirstName(firstName)
}
This will always call findByFirstName from UserBusinessDelegate (because you're using self, which basically says that this object will have this kind of behaviour at runtime, not that it's parent will have it and therefore we should call parent's method) creating a new stack frame with each call -> stack overflow.
In the second snippet UserBusinessDelegate's findByFirstName will be called and then you call MockUserRepository's method from it using super -> no recursion -> no stack overflow. You can check Scala's stackable trait pattern for more info.
#Edit: to make it more clear, in the snippet that throws a SO exception the findByFirstName method from MockUserRepository won't be called because you are overriding it in UserBusinessDelegate therefore the anonymous class created with new MockUserRepository with UserBusinessDelegate will only contain the overriden method and that's why the SO, is that clear?
Why would you assume that the method from MockUserRepository would get invoked?
#Edit2: the code doesn't compile without override because self: UserRepository => tells the compiler that a method with such a signature will already be there at runtime and you cannot have 2 methods with the same signature. The first example works only because it's a stackable trait, such traits are dynamically bound and can modify the behaviour but have to call super at some point (which normally isn't allowed without the abstract override modifier, I really recommend going through the link I posted about stackable pattern).
Maybe someone else knows a way, from what I know there's no way to call the mock method unless you change the method name in UserBusinessDelegate and drop the override, then you can call self.findByFirstName and it will call the method from MockUserRepository.
I am wanting to test one of my akka actors, it uses slick to get the information from the database. In my actor I have this bit of code
CardStationPermissions.retrieveByStationID(stationID).foreach(card => {
I want to know how can I mock that function to change the output instead of relaying on whats in the database?
It's really difficult to mock things that are being called in a static way (in this case, a call on an object as opposed to an instance of a class). When you need to be able to mock and test things like this, I tend to agree with Mustafa's suggestion that creating a trait to represent the relevant methods to mock. A simple example would look as follows:
case class MyObject(id:Long)
trait MyDao{
def getData(input:String):List[MyObject] = ...
}
object MyDao extends MyDao
class MyActor extends Actor{
val myDao:MyDao = MyDao
def receive = {
case param:String => sender ! myDao.getData(param)
}
}
Here you can see that I have a trait to represent my dao methods (only 1 for this example) and then I mix that trait into a scala object as the default instantiation of that trait. When I setup my dao in my actor, I explicitly type it to the trait so that I can substitute a mock impl of that trait later.
So then if I wanted a simple test showing mocking, it could look something like this (via specs2):
class MyActorTest(_system:ActorSystem) extends TestKit(_system)
with Specification with Mockito with ImplicitSender{
def this() = this(ActorSystem("test"))
trait scoping extends Scope{
val mockDao = mock[MyDao]
val actor = TestActorRef(new MyActor{
override val myDao = mockDao
})
}
"A request to get data" should{
"pass the input to the dao and return the result to the sender" in new scoping{
mockDao.getData("foo") returns List(MyObject(1))
actor ! "foo"
expectMsg(List(MyObject(1)))
}
}
}