Provide interfaces to facilitate testing/mocking

Some of Akka’s API are final classes, e.g. HttpExt or CoordinatedShutdown, which makes unit testing code which uses these pretty hard. Mockito has some support for even mocking final classes, but that is based on agents and instrumentation and opens a whole can of worms.

Wouldn’t it make sense to provide (abstract) interfaces for the implementations?

Mocking with mockito (which is great, don’t get me wrong) though is not quite safe in concurrent settings the last time I checked?

Http specifically, if talking about the client, is not really “the thing you pass around”, rather usually wrapped in something you can mock yourself…

E.g. Flows — easy to replace with your mocks, or your own type — easy to replace with your mocks.

Is there more specific cases you can highlight?

Think about this use case: There is an actor, which (a) brings an API into being via HttpExt.bindAndHandle and (b) if successful registers with coordinated shutdown via shutdown.addTask.

In order to do that I think I have to pass HttpExt and CoordinatedShutdown into the method that creates the behavior and mock them in the tests. Or do you see other ways?

And you want to test what exactly there? If just “if right method was called” I’d argue that in this case rather test the behavior is actually correct - the hook triggers, the thing is bound etc?

Yes, in unit tests I would like to ensure that the right methods were called with the expected arguments. In unit tests it’s not only hard (or at least inconvenient) to test that the system has terminated or some port has been bound (or not), but that’s rather something for larger scoped tests, e.g. integration tests.

Is there a reason to not provide interfaces? Back in good old Spring days providing interfaces (programming for interfaces) for services (HttpExt and CoordinatedShutdown clearly are service objects) was considered good style and I believe this is still true.

Feel free to open a ticket, but bear in mind binary compatibility. Perhaps possible to pull off - PoC welcome.
Though I remain not a fan of tests that check “if right parameter is passed”; those are like pouring cement over your app.

I agree with you, this testing style often is not the right approach. Yet in some cases it makes a lot of sense. In my example it prevents from accidental regressions (I have seen a new release of some software go into production that no longer properly used CoordinatedShutdown which resulted in some nasty production issues).

1 Like

My concern with removing such final or defining too many extension points with interfaces or abstract classes is that it makes it even more difficult to maintain binary and source compatibility. It would make it difficult for us to evolve those classes. For example we would not be able to add new methods with risk of breaking user code.

Hmm … adding methods would break hand written mock classes. And maybe behavior of automated ones. But hey, that’s just test code.

mockito-inline is pretty awesome in theroy, because you can mock everything, but due to instrumentation it leads to deadlocks during (parallel which is sbt’s default) test execution.

I think even a sealed trait would do the job!