Features
This is an overview of Scala3Mock features. Some section in this page have a dedicated page as well. Those pages will be indicated when present.
Do note that although the authors tried to be thorough when writing this page, some features might have slipped through the cracks. All supported use cases are covered by a test in the core/features and core/mock packages.
Scala3Mock provides fully type-safe support for almost all Scala features.
This includes:
- mocking classes, traits and case classes
- mocking functions and operators
- mocking type parametrised and overloaded methods
- support for type constraints
- support for repeated parameters and named parameters
- mocking Java classes and interfaces
Before going over the various features, let's define some types and import we can use along the way.
trait Heater {
def isReady: Boolean
}
class CoffeeMachine(heater: Heater) {
def powerOn(): Unit = ()
def powerOff(): Unit = ()
def isOn: Boolean = ???
}
case class Player(name: String, country: String)
case class Message(content: String)
abstract class Database {
def getPlayerByName(name: String): Player
def sendMessage(player: Player, message: Message): Unit
def someMethod(s: String, d: Int): Int
def otherMethod(s: String, d: Float): Int
def increment(i: Int): Int
}
// And import the scala3mock content.
import eu.monniot.scala3mock.ScalaMocks.*
Mocking
Scala3Mock can create mock out of classes (abstract or not, with parameters or not) and traits.
val heaterMock = mock[Heater]
// heaterMock: Heater = repl.MdocSession$MdocApp$HeaterMock$1@6d4c93f3
val dbMock = mock[Database]
// dbMock: Database = repl.MdocSession$MdocApp$DatabaseMock$1@639a1401
Argument matching
// expect someMethod("foo", 42) to be called
when(dbMock.someMethod).expects("foo", 42)
// res0: CallHandler2[String, Int, Int] = <features.md#L57> Database.someMethod(foo, 42) once (never called - UNSATISFIED)
// expect someMethod("foo", x) to be called for some integer x
when(dbMock.someMethod).expects("foo", *)
// res1: CallHandler2[String, Int, Int] = <features.md#L57> Database.someMethod(foo, *) once (never called - UNSATISFIED)
// expect someMethod("foo", x) to be called for some float x that is close to 42.0
when(dbMock.otherMethod).expects("foo", ~42.0)
// res2: CallHandler2[String, Float, Int] = <features.md#L57> Database.otherMethod(foo, ~42.0) once (never called - UNSATISFIED)
// expect sendMessage(receiver, message) for some receiver with name starting with "A"
when(dbMock.sendMessage).expects(where { (receiver: Player, message: Message) =>
receiver.name.startsWith("A")
})
// res3: CallHandler2[Nothing, Nothing, Unit] = <features.md#L57> Database.sendMessage<function1> once (never called - UNSATISFIED)
Call Ordering
Mock ordering is not currently supported in Scala3Mock. If you wish it to be, please chime in on issue #6.
Call count
// expect message to be sent twice
when(dbMock.sendMessage).expects(*, *).twice
// expect message to be sent any number of times
when(dbMock.sendMessage).expects(*, *).anyNumberOfTimes
// expect message to be sent no more than twice
when(dbMock.sendMessage).expects(*, *).noMoreThanTwice
Returning values
when(dbMock.getPlayerByName).expects("Hans").returning(Player(name="Hans", country="Germany"))
when(dbMock.getPlayerByName).expects("Boris").returning(Player(name="Hans", country="Russia"))
Throwing exceptions
when(dbMock.getPlayerByName).expects("George").throwing(new NoSuchElementException)
Call Handlers
If your mock needs to do more complex calculation, onCall
will let you do exactly that:
when(dbMock.increment).expects(*).onCall {
case 0 => throw RuntimeException("0 will throw")
case arg => arg + 1
}.twice
// compute returned value
assert(dbMock.increment(100) == 101)
// throw computed exception
try dbMock.increment(0)
catch e => println(s"caught $e")