Skip to main content

πŸš€ Demystifying JUnit Testing with Mockito & Spring Extensions

πŸ‘‹ Before diving deep into testing, I always assumed:


"JUnit is just something you use with @Test… it just works!"

 

But once I actually started exploring test frameworks in real-world projects, I realized there's so much more behind the scenes.


So here’s a blog to clarify the confusion, make it visually digestible, and hopefully save you some debugging hours. Let’s roll! 🧠✨


πŸ” Step 1: What dependencies should I include for JUnit?

You may have seen these terms in your build.gradle:

testImplementation 'org.junit.jupiter:junit-jupiter:5.10.0' implementation 'com.example:some-library:1.2.3'

But wait... what’s the difference? πŸ€”

✅ implementation

  • This means: Include the library for both compile time AND runtime.

  • It will be packaged inside the final JAR/WAR.

  • Use it for things your production code needs.

πŸ§ͺ testImplementation

  • This means: Use it only during test execution.

  • It will NOT be added to the production JAR/WAR.

  • Perfect for JUnit, Mockito, and other test libraries.

🎯 Rule of thumb:


If it’s only used in test code, stick with testImplementation.


🧩 Step 2: Mockito vs Spring Extension — When to Use What?

You might have seen these annotations:


@ExtendWith(MockitoExtension.class) // JUnit + Mockito

@SpringBootTest                    // Spring Integration Test

Let’s decode them:

πŸ§ͺ Use @ExtendWith(MockitoExtension.class):

  • Ideal for pure unit tests.

  • You’re mocking everything and not relying on Spring context.

  • Example: Testing service logic with fake repositories.

πŸ§ͺ Use @SpringBootTest:

  • This loads the full Spring context — all your beans!

  • Perfect for integration testing.

  • You’re testing real method calls, configs, and actual Spring beans.


🧠 Step 3: What about @Mock, @InjectMocks, and @MockBean?


Let’s simplify:

Annotation      Comes FromUse Case
@Mock        Mockito                       Mock a single class/bean
@InjectMocks        Mockito                Inject mocked dependencies into the real class
@MockBean         Spring             Replace a bean in the Spring context with a mock


πŸ”§ Example:
@Service public class MyService { private final MyRepo repo; public MyService(MyRepo repo) { this.repo = repo; } public String getData() { return repo.fetch(); } }

@ExtendWith(MockitoExtension.class) class MyServiceTest { @Mock MyRepo mockRepo; @InjectMocks MyService service; // Test with mocked repo! }

🧠 If you're using @SpringBootTest, prefer @MockBean to mock actual Spring beans during integration.


πŸ’₯ Step 4: Why do my integration tests break after adding a config?

Let’s say you added a new config:


@Configuration public class PubSubConfig { @Bean public PubSubTemplate pubSubTemplate() { return new PubSubTemplate(...); // Requires real credentials } }

Suddenly... πŸ’£ Your tests are failing!

🀯 Why?

Because:

  • @SpringBootTest loads the entire Spring context.

  • It tries to initialize your new bean.

  • If it needs real credentials, BOOM — your test explodes.

πŸ›  Fix?

@MockBean private PubSubTemplate pubSubTemplate;

This mocks the bean during testing and avoids loading the real implementation.

πŸ“ Bonus Tip:
Spring test uses application-test.properties. If required values are missing there, config loading can fail too.


πŸ§ͺ Step 5: @ParameterizedTest vs @Test


AnnotationRuns how many times?Purpose
        @Test    Once         For static, fixed tests
 @ParameterizedTest        Multiple       Repeats test for each input set

Example:
@ParameterizedTest @ValueSource(strings = {"Hello", "JUnit"}) void testWithParams(String input) { assertNotNull(input); }

πŸ’‘ Use @ParameterizedTest when the same logic needs to be tested against multiple inputs!



πŸ”š Wrapping Up

This post hopefully saves you from chasing vague test errors across JUnit, Spring, and Mockito setups.

  • Use @MockBean when Spring tries to load a bean you don’t want in tests.

  • Use @ExtendWith(MockitoExtension.class) for isolated unit tests.

  • Use @SpringBootTest for real context-driven tests — but be mindful of config pitfalls!

  • Choose the right annotations for what you’re testing.


πŸ—£ Have you faced crazy test failures or mocking nightmares lately? Share your stories or tricks in the comments — let’s learn together!


Until next time,
– Anand ☕ @ Java Bean Bag

Comments

Popular posts from this blog

🐱 Tomcat vs ⚡ Netty – Which One Should You Use?

🐱 Tomcat vs ⚡ Netty – Which One Should You Use? So recently I got curious about this too πŸ€”. Everywhere in Spring Boot tutorials we see Tomcat . Then suddenly while exploring Spring WebFlux , the name Netty pops up. And I was like – “Wait, who’s this Netty guy trying to replace Tomcat?” πŸ˜… Let’s break it down with real-time examples , icons , and fun comparisons . 🐱 Tomcat – The Traditional Web Server Type: Servlet Container (blocking I/O) World: Used with Spring MVC Style: Thread-per-request model πŸ‘©‍πŸ’» Pros: Stable, widely used, battle-tested Cons: Struggles with huge concurrent connections πŸ‘‰ Example in real life: Tomcat is like a restaurant with fixed waiters 🍴. - Each customer = one thread/waiter - If too many customers come in at once → waiters run out → customers wait outside πŸšͺ ⚡ Netty – The Reactive Rockstar Type: Asynchronous Event-Driven Network Framework World: Default for Spring WebFlux Style: Event-lo...

🎭 Spring’s Secret: Why @Transactional & Friends Betray You Silently

πŸ’‘ Lesson Learned — Not a Prod Bug, But a Real Pain No, this wasn’t a production outage. Nobody screamed at me. But I sat for 3 hours wondering: “Why the heck is my @Transactional not rolling back!?” 😡‍πŸ’« “Why is Redis cache not working?” 🀯 Turned out, the issue was one silent villain: 🧱 Self-invocation 🀷 What Is @Transactional ? If you're new: @Transactional = Tells Spring to start a DB transaction when a method is called. It’ll commit if everything’s okay. It’ll rollback if something fails. 🧠 Think of it like wrapping your code in: try { beginTransaction(); // your logic commit(); } catch(Exception e) { rollback(); } πŸ•΅️ Real-Life Analogy — The Gateway Community 🏘️ Let me tell you about my society — it has a strict watchman at the gate. Here’s how it works: πŸ›‚ Watchman = Spring Proxy 🏠 Your apartment = Your service class πŸšͺ Your room = A method inside that class πŸƒ Scenario 1: Outsider Visits Your friend from outside...

🧡 Virtual Threads in Java — The Ultimate Guide with Diagrams, Code & Interview Qs!

πŸš€ “How are Virtual Threads different from Thread Pools?” 😡 “Are they OS threads or JVM threads?” πŸ™ƒ “Should I still use CompletableFuture?” 🀯 “How do I even use them in real-time microservices?” 🧠 What are Virtual Threads? Virtual Threads (introduced in Java 21 as stable πŸŽ‰) are lightweight threads managed by the JVM instead of the OS kernel. πŸ‘‰ They look like normal threads, but don’t hog OS resources like traditional threads. 🧠 What is the OS Kernel? πŸ›️ OS Kernel = The Brain of the Operating System It’s the core part of your OS (Windows, Linux, Mac) that: Manages memory 🧠 Schedules threads πŸ•’ Talks to hardware πŸ’» Handles I/O operations πŸ“¨ When you create a traditional thread in Java, the JVM asks the OS Kernel to create a real OS-level thread. πŸ–Ό️ Imagine This... ┌───────────────────────────┐ │ Your Java Application │ └────────────┬──────────────┘ │ ...