0

Say I have the following:

@ImplementedBy(classOf[DefaultFoo])
trait Foo {
  def a (s : String) : Int
}

class DefaultFoo @Inject()() extends Foo{

  override def a (s : String) = 1

}

@ImplementedBy(classOf[DefaultBaz])
trait Baz {
  def b (s : String) : Int
}

class DefaultBaz @Inject()(val f :Foo) extends Baz{

  override def a (s : String) = 1

}

If I want to test, say DefaultBaz, I am normally using ScalaMock and I would mock as follows in my test spec:

class DefaultBazSpec extends AnyWordSpec with MockFactory{

   val mockFoo = mock[Foo]
val b = new DefaultBaz(mockFoo)

   // write tests
}

But I could also do this:

val mockFoo = mock[DefaultFoo]

Which one is better? Mock the trait or the default class implementation?

Mojo
  • 1,152
  • 1
  • 8
  • 16
  • 1
    Why not just extending the trait with a simple class that does what the mock would do but without reflection and fancy syntax. – Luis Miguel Mejía Suárez Jan 25 '21 at 18:57
  • I didn't give a good example. I wanted to describe a scenario where `Foo` is injected into another class. And the tests for that class would use a mocked version of `Foo` using Scalamock. Now I could do `mock[Foo]` or `mock[DefaultFoo]` . I wanted to know the pros and cons of that – Mojo Jan 25 '21 at 19:52
  • I think you have some errors in your snippet, you probably want `DefaultBaz` to extend `Baz` and to receive an instance of `Foo` as an argument. - anyways, I know that you are used to java way of doing things with reflection to solve _(complicate)_ every trivial problem like passing dependencies and testing. But, many people in Scala prefer to keep things simple and just pass dependencies manually and use simple stubs for testing instead of mocks. – Luis Miguel Mejía Suárez Jan 25 '21 at 20:16
  • Yes sorry I fixed that and also show that I am using Guice DI framework. I know that FP approach says don't use DI but I am using Play Framework and it comes with Guice DI so I am using that, that's why I am testing this way, – Mojo Jan 25 '21 at 20:27
  • Again, in this case, you really do not need to mock, you can just create dummy class that extends `Foo` and provide there the false implementation that you would do with a mock and pass an instance of that class to `DefaultBaz` to test ti. But, if you prefer to keep using mocking for whatever reason _(consistency with the rest of the codebase is a good reason)_ then I would guess you should mock `Foo` – Luis Miguel Mejía Suárez Jan 25 '21 at 20:30
  • Thanks @LuisMiguelMejíaSuárez - yes that's what I do now. But if I was to mock DefaultFoo would that be bad? – Mojo Jan 25 '21 at 20:40
  • 1
    Mainly because your `DefaultBaz` should work for any `Foo` and also because mocking `DefaultFoo` may be harder than a plain interface _(which btw, doesn't need mocking, but you must be tired of me repeating it over and over again)_. – Luis Miguel Mejía Suárez Jan 25 '21 at 20:42
  • Yes that's what I thought. What if DefaultFoo required 5 dependencies to be injected. I certainly don't want to spend time doing that just to mock some behaviour of the `a` method. So I mock `Foo` instead and I don't need to get involved in all that. – Mojo Jan 25 '21 at 20:46
  • Does this answer your question? [Mocking a class vs. mocking its interface](https://stackoverflow.com/questions/9226323/mocking-a-class-vs-mocking-its-interface) –  Jan 25 '21 at 21:22

1 Answers1

2

Better to use neither. Mocking should be in general avoided (especially in Scala).

But even if you decided to proceed with mocks, mocking the class under test destroys the whole purpose of testing: the code under test has nothing in common with the production code.

Mocks are for mocking dependencies (e.g. constructor parameters or method arguments) of the class under test.

simpadjo
  • 3,947
  • 1
  • 13
  • 38
  • The way I use mocks is to mock the behaviour of the methods in the class in the above example. So say for example, I had another class that injected `Foo`. Then in my test for this other class I would just do `val f = mock[Foo]` and then write the mocks for the behaviour of method `a` so they can be use to test this other class. See my updated post. It describes the scenario better – Mojo Jan 25 '21 at 19:48
  • Then mocking `Foo` is a lesser evil – simpadjo Jan 25 '21 at 20:39
  • What is evil about mocking the DefaultFoo - that's my main question @simajdo – Mojo Jan 25 '21 at 20:41