7

I have a Scala object and it contains a few utility functions. These functions are called by other functions present in the same object or from other classes/objects. Is it possible to mock this object or the functions so that I can unit test the classes where they are being called.

Example:

object Util {

  def methodA() = { 
    //other code
    methodB() 
    //other code
  }

  def methodB() = { 
    //other code
    methodC() 
    //other code
  }

  def methodC() = { ... }

}

And here I'm calling the object function from another class

class Data {

  //other code

  def call() = {
    //other code
    Util.methodA()
    //other code
  }
}

How can I go about unit testing the function call() of class Data ? In Java I can create a mocked object for Util and set expectations for a call to methodA(), but this is not possible in Scala since no mocking library supports mocking of a Scala object.

Xavier Guihot
  • 54,987
  • 21
  • 291
  • 190
noober
  • 164
  • 1
  • 2
  • 10
  • There are many scala mocking options. See http://www.scalatest.org/user_guide/testing_with_mock_objects for example. Any quick search will bring you many options – Assaf Mendelson Apr 18 '17 at 15:17
  • 1
    Yes I have already seen the link that you have provided, but none of the mocking frameworks mentioned there support mocking of Scala objects. ScalaMock 2 supported mocking of objects but it has been discontinued in ScalaMock 3, which is latest version for Scala 2.11 compiler. – noober Apr 19 '17 at 06:15

2 Answers2

13

The problem in some sense is that you've used a pattern that is similar to a static class in Java. You can't mock static classes, which is why Java patterns often don't favor that approach.

On the other hand, in Scala you can. Make Util extend a trait and implement it.

trait UtilityMethods {
 def methodA()
 def methodB()
}

object Utils extends UtilityMethods {
  def methodA() = {}
  def methodB() = {}
}

And then in your test:

val mockedUtils = mock[UtilityMethods]

(using mockito). Obviously you will have to pass UtilityMethods around your code instead of Utils, just like you would wth an interface in Java.

In general, you can also use implicit scoping to inject functions and thus mock those dependencies without a static-like object approach, but the above is pretty close to Java patterns and should feel pretty comfortable.

Keith Nordstrom
  • 354
  • 2
  • 9
  • Can you show with an example how to use implicit scoping ? – noober Apr 19 '17 at 04:56
  • 3
    Sure. There are a few ways to go about it. I often use implicits when I'm looking for a DI approach because they are similar patterns - a provided dependency being injected by an external actor. In this case, think `class Data(implicit utils: UtilityMethods)` and then the rest follows - provide your implementation of UtilityMethods where required. You could also use [implicit classes](http://docs.scala-lang.org/overviews/core/implicit-classes.html) to put those methods on `Data` itself. Each is a method of avoiding the "static" pattern while also keeping those dependencies out of the way. – Keith Nordstrom Apr 19 '17 at 18:33
0

This might not be a perfect fit for all scenarios but if you have a function you are passing into other classes say and you want to mock it in your unit tests you can create a class that extends a function definition and mock that:

  class Increment extends (Int => Int) {
    def apply(i: Int): Int = {
      i + 1
    }
  }
  case class IncrementFactory(incrementer: Int => Int)

  val incFactory = IncrementFactory(new Increment)
  incFactory.incrementer(3)

  def testIncrementFactory: Unit = {
    val incrementer = mock[Increment]
    when(incrementer.apply(any())).thenReturn(4)
    
    val factory = IncrementFactory(incrementer)
    assert(factory.incrementer(3) == 4) 
  }
UnitasBrooks
  • 1,062
  • 7
  • 15