0

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?

1
  • 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. Commented Dec 22, 2017 at 14:44

1 Answer 1

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.

1
  • 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
    Commented Dec 22, 2017 at 16:01

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.