Search code examples
scalamockitospecs2

using mockito to mock a scala object call inside a function


I'm trying to test the following function

class someClass {
    def someMethod() = {
        val x = someObject.someOtherMethod()
        //some logic that i want to test 
    }
}

Is there a way to mock val x or the someOtherMethod call without passing x


Solution

  • If SomeObject is truly an Object, I don't believe there is, short of some reflection black magic.

    A common pattern is to have a trait that defines the public methods of the object, and have the object extend the trait.

    Now SomeClass can depend on the SomeObject trait: e.g.

    trait SomeObject {
      def someMethod: Unit
    }
    
    object SomeObject extends SomeObject {
      def someMethod = println("real method called")
    }
    
    class SomeClass(someObject: SomeObject)
    

    and In tests you can mock the trait:

    val mockObject = mock[SomeObject]
    when(mockObject.someMethod).thenReturn(())
    val someClass = new SomeClass(mock[SomeObject])
    

    edit: Some Unsafe magic.

    import sun.misc.Unsafe
    
    object Foo {
      val length: String => Int = {s => s.length}
    }
    
    Foo.length("foo") // 3
    
    val unsafe = {
      val f = classOf[Unsafe].getDeclaredField("theUnsafe")
      f.setAccessible(true)
      f.get(null).asInstanceOf[Unsafe]
    }
    
    val offset = unsafe.objectFieldOffset(Foo.getClass.getDeclaredField("length"))
    val doubleLength: String => Int = { s=> s.length * 2}
    unsafe.putObject(Foo, offset, doubleLength)
    
    Foo.foo("foo") // 6
    

    Unfortunately I couldn't make this work when Foo.length is a def and not a val