0

I have a scala class A and there is a method doSomething in it.

There is another class B

  class B(name: String)

there is another class C

class C {
 def doSomethingElse(b: B): String { 
 /// some logic 

 ////

 }
} 


 class A(c: C) {
  def doSomething(uuid: UUID): String {
   val b = new B("hello)
   c.doSomethingElse(b)
   // some logic

 }

}

Now I want to test the method doSomething of class A using scalatest and scalamock

and I tried to mock the call doSomethingElse

val mockC = mock[C] 
val b = new B("hello")
(mockC.doSomethingElse _).expects(b).returning("A");

but when the actual call happens , the mock does not get satisfied because the object of B is different. Is there a way to express this mock so that it gets satisfied ?

user9920500
  • 606
  • 7
  • 21
  • 2
    If you want `new B("hello")` to be treated as equal to another `new B("hello")`, you have to implement `.equals` accordingly. By default, Java instance identity is used (only same instance is equal). If `B` can be a case-class, you get this for free. – Thilo Sep 28 '19 at 09:56

2 Answers2

1

Thilo's comment is right - your two Bs would be compared as references above, and as they are not the same object, they are not equal. For content equality, you need an appropriate equals implementation. You get that for free in Scala if you make B a case class. If you can't change class B though, then using a predicate mather in ScalaMock might help you to compare the two instances during the test. Read up on it here: https://scalamock.org/user-guide/matching/

Philipp
  • 967
  • 6
  • 16
  • but mine is not case class and it does not have to be just for making the tests pass. Is there any other trick that can be followed only for tests ? – user9920500 Sep 28 '19 at 12:34
  • Did you read about and try the predicate matcher yet as I advised above? If that doesn't work for you, then there is no way, as fundamentally, it's just how the JVM works. – Philipp Sep 28 '19 at 20:40
0

Here are examples suggested by @Thilo and @PhilippM:

Overriding equals method like so

class B(val name: String) {
  override def equals(obj: Any): Boolean = obj match {
    case b: B => b.name == this.name
    case _ => false
  }
}

we can use regular

(mockC.doSomethingElse _) expects(new B("hello")) returning("A")

or if we cannot modify B then try predicate matching like so

mockC.doSomethingElse _ expects where { (b: B) => b.name == new B("hello").name } returning "A"
Mario Galic
  • 47,285
  • 6
  • 56
  • 98