Mock - ALawliet/backend GitHub Wiki

things to unit test:

  • a class, a function, a unit under test

inversion of control

  • if things are done well, you program interfaces, then you can mock those interfaces
  • in order to properly test a class, u need to know what class depends on
  • so you pass those dependencies into the class
    • don't create dependencies in your class, create them outside (pref with interfaces, so they can be mocked), then pass them in
I cant believe anyone has mentioned this yet :/

Look up "Inversion of control"

A brief summary is about taking things your code depends on created in your class and passing them in when you create the class instead.

IoC is really powerful because if you want to test code, you need to control anything it depends on / calls out to.

So when you are using IoC and passing your dependencies into your class, then Mockito is powerful because it provides an easy way to "mock" your dependencies and ways to control how they act.

That way you can pass in mocks to your class + test code deterministically without having to manipulate the dependencies weirdly or doing the whole "fake" implementation of an interface (which essentially is what Mockito is doing, just by reflection + making up code on the fly)

unit tests

  • only use one real object/unit, the rest needs to be mocked
  • that way if something fails, you know it was that one unit

things to mock:

  • external calls, where u know the input and output
  • exceptions
  • interfaces
    • unit -> (interface) -> outside world
    • public List getAllCustomers() -> thenReturn
  • a function was called n times
  • a function was called with specific args which led to specific functionality
  • Dog has a vet, mock vet.getMedicine() bc don't care how vet gets medicine (external db call, etc), use to unit test Dog class when different medicines are returned
  • u want to test A, but A depends on B and C, so mock B and C
    • in controller -> service -> repo, when testing controller, you don't wanna test your service and repo, so mock those
  • database calls
  • sending emails
  • at the boundary of a service
  • mock the Repository and the Service interfaces (that you control), but not the http library (that you do not control)

things to not mock:

  • the class under test
  • the libraries themselves, like Connection
  • types you do not own, like EntityManager
  • Java, anything the compiler could catch on its own
Disclosure: I work at AtomicJar

After trying several approaches, my current testing looks like:

Use Mocks only when necessary.

Prefer testing with real services using [Testcontainers](https://testcontainers.com/) (If I use Postgres in prod then I test with Postgres using Testcontainers instead of H2 in-memory db)

Write Repository tests using (@)DataJpaTest, (@)DataMongoTest etc only for custom methods.

Test business-logic in the service layer using plain JUnit without any Spring magic involved

Write Unit tests for Controllers using (@)WebMvcTest to verify failure scenarios.

Write Integration Tests using Testcontainers, TestRestTemplate/RestAssured/WebClient.

Mock any external REST API calls using WireMock/MockServer.
⚠️ **GitHub.com Fallback** ⚠️