18

I am using mockito and trying to mock a scala object.

object Sample { }
//test
class SomeTest extends Specification with ScalaTest with Mockito {
    "mocking should succeed" in {
        val mockedSample = mock[Sample]
     }
}

This gives me two compilation errors.

error: Not found type Sample
error: could not find implicit value for parameter m:
scala.reflect.ClassManifest[<error>]

If I change Sample from object to class it works. Is is possible to mock scala objects with mockito? If yes how?

keiter
  • 3,534
  • 28
  • 38
scout
  • 2,336
  • 4
  • 21
  • 22

4 Answers4

18

As written, your Sample is a pure singleton. Its type is its own and there is only one member of that type, period. Scala objects can extend another class (possibly abstract, if it supplies the necessary definitions to make it a concrete) and traits. Doing that gives it a type identity that includes those ancestors.

I don't know what Mockito is really doing, but to my mind, what you're asking for is strictly at odds with what a Scala object is.

Randall Schulz
  • 26,420
  • 4
  • 61
  • 81
  • 3
    Definitely agree here. You might be able to try mock[Sample.type], but I doubt it would work in practice. I'd recommend having Sample extend some interface trait and mock it out that way. The big issue is that if you want to inject your mock in place of the singleton Sample, you'll have to do some nice, evil, fun reflective magic. If you're interested, We can post that. – jsuereth Aug 26 '10 at 14:56
  • I was looking at the Mockito source code the other day to answer a related question (which for some reason I cannot find, now) and I seem to recall seeing one of the "mock" generators that just returns a specific value rather than trying to generate alternates / variants. – Randall Schulz Aug 26 '10 at 15:14
  • Is there some way to do this with Powermock or the like? If I have a (effectively global) method on a companion object, it seems reasonable to want to mock it's behaviour; certainly this is a common pattern in the ruby world. – Korny Feb 01 '11 at 03:23
  • 1
    jsuereth, I know this is an old post, but I'd like to know the way to inject a mock to a singleton object. Thanks. – k4200 Jun 14 '11 at 02:02
15

Keep in mind that you can mock the methods of an object if you lift them to functions.

case class Person(name: String)
object Person {
  def listToJson(lp: List[Person]) = "some actual implementation"
}

class ClassUnderTest(listToJson: (List[Person]) => String = Person.listToJson(_)) {
  def testIt(lp: List[Person]) = listToJson(lp)
}

import org.specs._
import org.specs.mock.Mockito
import org.mockito.Matchers._  

class ASpec extends Specification with Mockito {
  "a thing" should {
    "do whatever" in {
      val m = mock[(List[Person]) => String]
      val subject = new ClassUnderTest(m)
      m(Nil) returns "mocked!"
      subject.testIt(Nil) must_== "mocked! (this will fail on purpose)"
    }
  }
}

Here I'm not mocking the object Person, but the method on it (which is probably what the OP was intending).

The test result shows the mocking works:

[info] == ASpec ==
[error] x a thing should
[error]   x do whatever
[error]     'mocked![]' is not equal to 'mocked![ (this will fail on purpose)]' (ASpec.scala:21)
[info] == ASpec ==

Meanwhile, the production-time usage of the ClassUnderTest is simply new ClassUnderTest due to the injected function being a default argument.

Synesso
  • 37,610
  • 35
  • 136
  • 207
10

Since version 1.16.0 of mockito-scala it is possible to mock Scala objects, you can check the docs here, but this is an example of how it would look like.

object FooObject {
 def simpleMethod: String = "not mocked!"
}

"mock" should {
 "stub an object method" in {
   FooObject.simpleMethod shouldBe "not mocked!"

   withObjectMocked[FooObject.type] {
     FooObject.simpleMethod returns "mocked!"
     //or
     when(FooObject.simpleMethod) thenReturn "mocked!"

     FooObject.simpleMethod shouldBe "mocked!"
   }

   FooObject.simpleMethod shouldBe "not mocked!"
 }
}
ultrasecr.eth
  • 1,437
  • 10
  • 13
8

I've recently released ScalaMock, a mocking library for Scala that can, among other things, mock singleton (and companion) objects.

Paul Butcher
  • 10,722
  • 3
  • 40
  • 44
  • 6
    On page provided, support for singleton and companion objects is declared under the section titled "Future Plans". Does framework currently support those features? – zbstof May 22 '13 at 11:51
  • 3
    @Zotov, it seems that the support for mocking objects is only available in ScalaMock2 with the use of a 2.9 compiler plugin, as explained in this [tutorial](http://paulbutcher.com/2011/11/06/scalamock-step-by-step/). ScalaMock3 doesn't require a compiler plugin since it relies on Scala 2.10 macros instead, but it doesn't support all of the features of ScalaMock2 yet, as mentioned in this [blog post](http://paulbutcher.com/2012/06/04/scalamock-3-0-preview-release/). Mocking objects is thus not supported in 2.10 ): As far as I can tell, that still seems to be the current state of the project. – Felix GV Jan 04 '14 at 04:38
  • 4
    ScalaMock's current documentation directly contradicts this answer. See the "Can I mock objects?" section in the [FAQ](https://scalamock.org/user-guide/faq/). – Noah Solomon Feb 27 '19 at 19:46
  • Noah seems to be correct to me. Is this answer even valid/correct (now)? – akki Sep 09 '19 at 11:46