-1

Typically, when writing unit tests I tend to need to stub out collaborators and also mock some behavior in one or more of the collaborating objects. Say if I am testing a Service that is using a Dao, I will need to inject a mocked dao in the constructor when setting up the test.

But

  1. creating new classes at runtime using ByteBuddy (used by Mockito) typically adds half a second or more to the initial startup time
  2. It's a tad bit hard to get the Mockito syntax right at times

I have come up short looking for ways of speeding up Mockito, but using mock libraries are not the only way to do this, though quite convenient in some terms:

  • Quick to use for simple things
  • Avoid having lots of one-off test dummy implementations littering the class hierarchy

How are people avoiding Mockito (and similar) when unit testing, and what are the pros/cons of each such alternative?

4
  • 2
    A few observations: (1) You can use mocks, or you can write your code in such a way that mocks are not required for unit testing, or at least the need for them is greatly reduced. (2) You can always make mock objects by hand. If that seems tedious, refer to observation 1. (3) Some things don't need to be unit tested. Sometimes a good integration test suffices. Commented Oct 5, 2023 at 13:22
  • The question might be badly worded, but I am actually most interested in the first bit: "write your code in such a way that mocks are not required for unit testing". How does that even work? You have dependencies, they might or might not do I/O, and if you want fast tests that avoid I/O you usually supply a test double. This might be written by me or created using a mocking library. Not sure how I can avoid that.
    – oligofren
    Commented Oct 5, 2023 at 16:32
  • I'm with @oligofren, I'm not sure how I would write code or design a system so that mocking is not required. Since you mentioned Mockito, I can tell you that mocking and testing of JVM apps generally became faster and easier when I adopted Spock (spockframework.org). It is BDD style (given/when/then) and Groovy based. There is a learning curve, particularly if you're not familiar with Groovy, but once you clear that hurdle tests are easy to write and mocking is simple leading to much more efficient test development in my opinion.
    – sceaj
    Commented Oct 10, 2023 at 3:03
  • @sceaj Wrt to designing a system to avoid mocking, the "Functional core/Imperative Shell" and "Clean Architecture"/Hexagonal Architecture, etc all support a kind of functional approach that would kind of let you specify in-data and test a simple out-data structure without resorting to stubbing out stuff with side-effects (since that's at the outer layer). That is quite understandable, but of course requires you design your system from scratch like that.
    – oligofren
    Commented Oct 12, 2023 at 13:07

1 Answer 1

1

Mocking was a thing long before mocking libraries were a thing.

To write a mock yourself just step between what you're testing and what you want to mock and pretend to be it.

This works well with the typical Arrange, Act, Assert testing pattern. Just set up your mock in arrange, act on it, then assert that it got what it was supposed to get.

Doing that might look like this:

@Test
public void testControler() {
    TestUseCases.PushMock interactorMock = new TestUseCases.PushMock();
    new ButtonControler(interactorMock).push();
    assertTrue( interactorMock.isPushed() );
}

Some people complain that you're just testing that a method was called. And they're right. But this isn't just any method. This is a method that sends a message out of this codebase. It's sending output. But it doesn't return anything. So all we can test is that it was called.

That is an ideal mocking situation. Because you can't simply rewrite that so that the method returns. When people ask for testable code often what they really want is functional code. And much of your behavior can be pushed down into functional code that returns something testable. But we don't just write functional code. Some of our code is Object Oriented code that sends messages using methods. When that crosses a significant boundary moving the method isn't an option. Mocking can make that testable.

What you can move is all interesting behavior code away from this boundary until the only code left here is boring structural code that doesn't do much and needs no more testing than a casual glance.

Mocking always has been and always will be a pain. It is worth the effort to rewrite your code to minimize the need for it. But it is something you can do with your existing language without asking for magic. None of this requires a mocking library. Just the discipline of knowing how to test this way.

Avoid having lots of one-off test dummy implementations littering the class hierarchy

Again, make mocking rare. Push interesting behavior down into testable code away from the significant boundaries that would require mocks.

3
  • I might have been a bit unclear, I was looking for different styles of testing or writing code that would avoid mocking.
    – oligofren
    Commented Oct 5, 2023 at 16:46
  • 1
    @oligofren sorry, your question seemed to be about alternatives to mock libraries. I can offer an example of avoiding mocking. Commented Oct 5, 2023 at 17:45
  • Here's another. The Functional Core Pattern does a good job making code testable without requiring mocks. Commented Oct 5, 2023 at 18:25

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.