Classic
Classic scalamock is the original project that has been available since the beginning. It provides a powerful and flexible way to create and use mocks and stubs in your tests.
It offers:
- Two mocking styles: Expectations-First Style (mocks) and Record-then-Verify (stubs)
- Scalatest and Spec2 integration
- Powerful features: Advanced expectations, call ordering, argument matchers and more
Getting Started
The first rule of scalamock is not to share any mocks and stubs between your test cases.
Usually - you should create some fixture/wiring to be reused in each test-case.
Scalatest
To use scalamock with scalatest - your suite should mixin org.scalamock.scalatest.MockFactory
//> using test.dep org.scalamock::scalamock:7.3.2
//> using test.dep org.scalatest::scalatest:3.2.19
import org.scalamock.scalatest.MockFactory
import org.scalatest.flatspec.AnyFlatSpec
class MyTest extends AnyFlatSpec, MockFactory:
trait Wiring:
val service1 = stub[Service1]
val service2 = stub[Service2]
val service3 = Service3(service1, service2)
it should "do something" in new Wiring {
// your test logic here
}
When testing with futures - you have two options:
- Mixin
org.scalatest.concurrent.ScalaFutures
and override patience configuration - Or use async suites like
AsyncFlatSpec
and mixinorg.scalamock.scalatest.AsyncMockFactory
class ExchangeRateListingTest extends AsyncFlatSpec with AsyncMockFactory {
val eur = Currency(id = "EUR", valueToUSD = 1.0531, change = -0.0016)
val gpb = Currency(id = "GPB", valueToUSD = 1.2280, change = -0.0012)
val aud = Currency(id = "AUD", valueToUSD = 0.7656, change = -0.0024)
"ExchangeRateListing" should "eventually return the exchange rate between passed Currencies when getExchangeRate is invoked" in {
val currencyDatabaseStub = stub[CurrencyDatabase]
currencyDatabaseStub.getCurrency.when(eur.id).returns(eur)
currencyDatabaseStub.getCurrency.when(gpb.id).returns(gpb)
currencyDatabaseStub.getCurrency.when(aud.id).returns(aud)
val listing = new ExchangeRateListing(currencyDatabaseStub)
val future: Future[Double] = listing.getExchangeRate(eur.id, gpb.id)
future.map(exchangeRate => assert(exchangeRate == eur.valueToUSD / gpb.valueToUSD))
}
}
Specs2
To use scalamock with specs2 you should run each test case in a separate fixture context that mixins org.scalamock.specs2.MockContext
//> using test.dep org.scalamock::scalamock:7.3.2
//> using test.dep org.specs2::specs2-core:5.6.3
import org.scalamock.specs2.MockContext
import org.specs2.mutable.Specification
class MySpec extends Specification {
trait Wiring extends MockContext {
val service1 = stub[Service1]
val service2 = stub[Service2]
val service3 = Service3(service1, service2)
}
"CoffeeMachine" should {
"not turn on the heater when the water container is empty" in new Wiring {
val waterContainerMock = mock[WaterContainer]
waterContainerMock.isEmpty.expects().returning(true)
}
}
}