ScalaTest with mocked object

807 Views Asked by At

I found some simple examples, but nothing works.

a model:

class Product() {
  var price: Int = 0
  var stock: Int = 0

  def addPrice(price: Int): Int = {
    this.price = price
    this.price
  }

  def addStock(qty: Int): Int = {
    this.stock += qty
    this.stock
  }
}

and my test class

classProductSpec extends AnyFlatSpec with MockFactory with OneInstancePerTest {
  val m = mock[Product]

  // suites (test examples)
  inAnyOrder {
   (m.addPrice _).expects(40).returns(40).once
   inSequence {
     (m.addStock _).expects(20).returns(20).once
     (m.addStock _).expects(10).returns(30).once
   }
  }

  // tests
  it should "set price" in {
    assert(m.addPrice(40) == 40)
  }

  it should "add new qty. Step 1" in {
    assert(m.addStock(20) == 20)
  }

  it should "add new qty. Step 2" in {
    assert(m.addStock(10) == 30)
  }
}

Every time, the error is:

Expected:
  inAnyOrder {
     inAnyOrder {
     <mock-1> Product.addPrice(40) once (never called - UNSATISFIED)
    ...
  }
}

If I run only one suite and one assert, it works:

(m.addPrice _).expects(40).returns(40).once
// tests
it should "set price" in {
  assert(m.addPrice(40) == 40)
}
1

There are 1 best solutions below

2
On BEST ANSWER

Let's explain the above code. The inAnyOrder section, defines assertions, for all tests. That means, that in each and every test in the suite, you should call exactly once to:

  1. m.addPrice(40)
  2. m.addStock(20)
  3. m.addStock(10)

while 2 must come before 3. Therefore, each test fails due to lack of 2 calls. For example, the test:

it should "add new qty. Step 1" in {
  assert(m.addStock(20) == 20)
}

fails with the message:

Expected:
inAnyOrder {
inAnyOrder {
    <mock-1> Product.addPrice(40) once (never called - UNSATISFIED)
    inSequence {
    <mock-1> Product.addStock(20) once (called once)
    <mock-1> Product.addStock(10) once (never called - UNSATISFIED)
    }
}
}

Actual:
<mock-1> Product.addStock(20)
ScalaTestFailureLocation: ProductSpec at (ProductSpec.scala:20)
org.scalatest.exceptions.TestFailedException: Unsatisfied expectation:

Because 1 and 3 were not satisfied.

If you'll try a test like:

it should "set price" in {
  assert(m.addPrice(40) == 40)
  assert(m.addStock(20) == 20)
  assert(m.addStock(10) == 30)
}

it will pass. Please note that if you change the order of 2 & 3, the same test will fail.