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

๐Ÿ” Is final Really Final in Java? The Truth May Surprise You ๐Ÿ˜ฒ

๐Ÿ’ฌ “When I was exploring what to do and what not to do in Java, one small keyword caught my eye — final . I thought it meant: locked, sealed, frozen — like my fridge when I forget to defrost it.”   But guess what? Java has its own meaning of final… and it’s not always what you expect! ๐Ÿ˜… Let’s break it down together — with code, questions, confusion, jokes, and everything in between. ๐ŸŽฏ The Confusing Case: You Said It's Final... Then It Changed?! ๐Ÿซ  final List<String> names = new ArrayList <>(); names.add( "Anand" ); names.add( "Rahul" ); System.out.println(names); // [Anand, Rahul] ๐Ÿคฏ Hold on... that’s final , right?! So how on earth is it still changing ? Time to dive deeper... ๐Ÿง  Why Is It Designed Like This? Here’s the key secret: In Java, final applies to the reference , not the object it points to . Let’s decode this like a spy mission ๐Ÿ•ต️‍♂️: Imagine This: final List<String> names = new ArrayList <>(); Be...

๐ŸŽข Java Loops: Fun, Fear, and ForEach() Fails

๐ŸŒ€ Oops, I Looped It Again! — The Ultimate Java Loop Guide You Won't Forget “I remember this question from one of my early interviews — I was just 2 years into Java and the interviewer asked, ‘Which loop do you prefer and why?’” At first, I thought, “Duh! for-each is cleaner.” But then he grilled me with cases where it fails. ๐Ÿ˜ต That led me to explore all loop types, their powers, and their pitfalls. Let’s deep-dive into every major Java loop with examples &  real-world guidance so you'll never forget again. ๐Ÿ” Loop Type #1: Classic For Loop — “The Old Reliable” ✅ When to Use: You need an index You want to iterate in reverse You want full control over loop mechanics ✅ Good Example: List<String> names = List.of("A", "B", "C"); for (int i = 0; i < names.size(); i++) { System.out.println(i + ": " + names.get(i)); } ๐Ÿ”ฅ Reverse + Removal Example: List<String> item...

๐Ÿงต 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 │ └────────────┬──────────────┘ │ ...