I have some Scala code that I wish to unit test using ScalaMock:
class CancellationManagerSpec extends FlatSpec with MockFactory {
"Cancelling a shipment" should "check shipment is not already shipped" in {
val manager = mock[CancellationsManager]
(manager.checkStatus _).expects(*, *).returning(true).once()
val request = CancellationRequestedEvent("shipmentNumber")
manager.processCancellation(request)
}
}
The test fails:
[info] - should complete a series of tasks in happy case *** FAILED ***
[info] Unexpected call: <mock-6> CancellationsManager.processCancellation(CancellationRequestedEvent(shipmentNumber))
[info]
[info] Expected:
[info] inAnyOrder {
[info] <mock-6> CancellationsManager.checkStatus(*, *) once (never called - UNSATISFIED)
[info] }
[info]
[info] Actual:
[info] <mock-6> CancellationsManager.processCancellation(CancellationRequestedEvent(shipmentNumber)) (Option.scala:121)
I want to test that when I process a cancellation, certain tasks are done. More generally, there is logic such as this that I would like to test:
class SalesOrderShippedProcess {
def execute(salesOrder: SalesOrder): Unit = {
if (doTask1() && doTask2()) {
doTask3()
doTask4()
doTask5()
}
}
def doTask1(): Boolean = ???
def doTask2(): Boolean = ???
def doTask3(): Boolean = ???
def doTask4(): Boolean = ???
def doTask5(): Boolean = ???
}
Where for some process, I want to check task 3, 4, and 5 are done only if task 1 and 2 is successful, and even if task 3 fails, task 4 and 5 should execute regardless.
What's the best way to test this? Is it failing because I'm calling a method of the mocked object directly? Do I need to move all the task methods to its own class then mock it, which seems a little strange to me just to be able to write a test for it?
-
You have two very different questions here - I'd suggest splitting the second half (from "I want to test that when I process a cancellation, certain tasks are done.") onwards into a separate question.Philip Kendall– Philip Kendall2017年12月22日 14:44:44 +00:00Commented Dec 22, 2017 at 14:44
1 Answer 1
Yes, you're doing this wrong - you should be calling a method on the real object (i.e. CancellationsManager
in your case), not on the mock. So your test would look a bit like:
it should "check the status when an order is cancelled" in {
val manager = new CancellationManager();
val request = new CancellationRequestedEvent("shipmentId");
manager.processCancellation(request);
(manager.checkStatus _).expects(*, *).returning(true).once()
}
Mocks are there to replace the dependencies of the object being tested, not the object itself - for example, if your CancellationManager
depended on an ShipmentFinder
, you would mock out the ShipmentFinder
so that you are testing only the CancellationManager
code, not all its dependencies as well.
-
Thanks, understood. I tried your code as well, and I get java.lang.NoSuchMethodException: services.CancellationsManager.mock$checkStatus 0ドル() So, looks like it's having trouble checking the method of the real object.Robo– Robo2017年12月22日 16:01:53 +00:00Commented Dec 22, 2017 at 16:01