Trait that can be mixed into a ScalaTest suite to provide
mocking support.
Trait that can be mixed into a ScalaTest suite to provide
mocking support.
class CoffeeMachineTest extends FlatSpec with ShouldMatchers with MockFactory {
"CoffeeMachine" should "not turn on the heater when the water container is empty" in {
val waterContainerMock = mock[WaterContainer]
(waterContainerMock.isEmpty _).expects().returning(true)
// ...
}
it should "not turn on the heater when the water container is overfull" in {
val waterContainerMock = mock[WaterContainer]
// ...
}
}
Sharing mocks across test cases
Sometimes multiple test cases need to work with the same mocks (and more generally - the same
fixtures: files, sockets, database connections, etc.). There are many techniques to avoid duplicating
the fixture code across test cases in ScalaTest, but ScalaMock recommends and officially supports
these two:
isolated tests cases - clean and simple, recommended when all test cases have the same
or very similar fixtures
fixture contexts - more flexible, recommened for complex test suites where single set of
fixtures does not fit all test cases
Isolated test cases
If you mix OneInstancePerTest trait into a Suite, each test case will run in its own instance
of the suite class and therefore each test will get a fresh copy of the instance variables.
This way in the suite scope you can declare instance variables (e.g. mocks) that will be used by
multiple test cases and perform common test case setup (e.g. set up some mock expectations).
Because each test cases has fresh instance variables different test cases do not interfere with each
other.
// Please note that this test suite mixes in OneInstancePerTestclass CoffeeMachineTest extends FlatSpec with ShouldMatchers with OneInstancePerTest with MockFactory {
// shared objectsval waterContainerMock = mock[WaterContainer]
val heaterMock = mock[Heater]
val coffeeMachine = new CoffeeMachine(waterContainerMock, heaterMock)
// you can set common expectations in suite scope
(waterContainerMock.isOverfull _).expects().returning(true)
// test setup
coffeeMachine.powerOn()
"CoffeeMachine" should "not turn on the heater when the water container is empty" in {
coffeeMachine.isOn shouldBe true// ...
coffeeMachine.powerOff()
}
it should "not turn on the heater when the water container is overfull" in {
// each test case uses separate, fresh Suite so the coffee machine is turned on
coffeeMachine.isOn shouldBe true// ...
}
}
Fixture contexts
You can also run each test case in separate fixture context. Fixture contexts can be extended
and combined and since each test case uses different instance of fixture context test cases do not
interfere with each other while they can have shared mocks and expectations.
class CoffeeMachineTest extends FlatSpec with ShouldMatchers with MockFactory {
trait Test { // fixture context// shared objectsval waterContainerMock = mock[WaterContainer]
val heaterMock = mock[Heater]
val coffeeMachine = new CoffeeMachine(waterContainerMock, heaterMock)
// test setup
coffeeMachine.powerOn()
}
"CoffeeMachine" should "not turn on the heater when the water container is empty" in new Test {
coffeeMachine.isOn shouldBe true
(waterContainerMock.isOverfull _).expects().returning(true)
// ...
}
// you can extend and combine fixture-contextstrait OverfullWaterContainerTest extends Test {
// you can set expectations and use mocks in fixture-context
(waterContainerMock.isEmpty _).expects().returning(true)
// and define helper functionsdef complexLogic() {
coffeeMachine.powerOff()
// ...
}
}
it should "not turn on the heater when the water container is overfull" in new OverfullWaterContainerTest {
// ...
complexLogic()
}
}
Trait that can be mixed into a ScalaTest suite to provide mocking support.
Sharing mocks across test cases
Sometimes multiple test cases need to work with the same mocks (and more generally - the same fixtures: files, sockets, database connections, etc.). There are many techniques to avoid duplicating the fixture code across test cases in ScalaTest, but ScalaMock recommends and officially supports these two:
Isolated test cases
If you mix
OneInstancePerTest
trait into aSuite
, each test case will run in its own instance of the suite class and therefore each test will get a fresh copy of the instance variables.This way in the suite scope you can declare instance variables (e.g. mocks) that will be used by multiple test cases and perform common test case setup (e.g. set up some mock expectations). Because each test cases has fresh instance variables different test cases do not interfere with each other.
Fixture contexts
You can also run each test case in separate fixture context. Fixture contexts can be extended and combined and since each test case uses different instance of fixture context test cases do not interfere with each other while they can have shared mocks and expectations.
See org.scalamock for overview documentation.