Bird
Raised Fist0
JUnittesting~15 mins

@InjectMocks annotation in JUnit - Deep Dive

Choose your learning style10 modes available
Overview - @InjectMocks annotation
What is it?
@InjectMocks is an annotation used in unit testing with JUnit and Mockito. It automatically creates an instance of the class under test and injects mock dependencies into it. This helps simplify setup by avoiding manual creation and wiring of objects. It works by scanning for fields annotated with @Mock or @Spy and injecting them into the tested class.
Why it matters
Without @InjectMocks, developers must manually create the class under test and inject all its dependencies, which is error-prone and verbose. This annotation saves time and reduces mistakes by automating dependency injection in tests. It makes tests cleaner and easier to maintain, improving developer productivity and test reliability.
Where it fits
Before learning @InjectMocks, you should understand unit testing basics, JUnit framework, and Mockito mocks. After mastering it, you can explore advanced Mockito features like argument captors, spies, and behavior verification. It fits in the journey of writing clean, maintainable unit tests with dependency injection.
Mental Model
Core Idea
@InjectMocks automatically creates the class you want to test and fills its dependencies with mocks so you can focus on testing behavior, not setup.
Think of it like...
It's like having a helper who builds a toy car for you and puts in all the fake parts you want to test, so you only need to check if the car works as expected.
┌─────────────────────────────┐
│       Test Class            │
│  ┌─────────────────────┐    │
│  │ @InjectMocks        │    │
│  │ TestedClass instance│    │
│  └─────────┬───────────┘    │
│            │                │
│  ┌─────────▼───────────┐    │
│  │ @Mock dependencies  │    │
│  │ (Mocks created here) │    │
│  └─────────────────────┘    │
└─────────────────────────────┘
Build-Up - 7 Steps
1
FoundationUnderstanding Unit Testing Basics
🤔
Concept: Learn what unit testing is and why isolating code parts matters.
Unit testing means checking small pieces of code (units) work correctly by themselves. It helps find bugs early and makes code safer to change. Usually, you test one class or method at a time.
Result
You know why testing small parts separately helps catch errors and improve code quality.
Understanding the purpose of unit testing sets the stage for using tools like @InjectMocks to make tests easier and more reliable.
2
FoundationIntroduction to Mockito Mocks
🤔
Concept: Mocks simulate real objects to isolate the class under test.
Mockito lets you create fake versions of classes called mocks. These mocks pretend to be real dependencies but let you control their behavior and check how your code interacts with them.
Result
You can create mocks to replace real dependencies and focus tests on the class you want to check.
Knowing mocks lets you isolate the tested class from outside influences, which is essential for reliable unit tests.
3
IntermediateManual Dependency Injection in Tests
🤔Before reading on: do you think manually creating and injecting mocks is easy or error-prone? Commit to your answer.
Concept: Manually creating the tested class and injecting mocks is possible but tedious and error-prone.
Without @InjectMocks, you write code like: @Test void test() { Dependency dep = mock(Dependency.class); TestedClass tested = new TestedClass(dep); // test code } This works but gets complicated if there are many dependencies.
Result
Tests become longer and harder to maintain as you manually create and inject each dependency.
Recognizing the pain of manual injection motivates using @InjectMocks to automate this setup.
4
IntermediateBasic Usage of @InjectMocks
🤔Before reading on: do you think @InjectMocks creates mocks or only injects existing ones? Commit to your answer.
Concept: @InjectMocks creates the tested class instance and injects mocks annotated with @Mock or @Spy automatically.
Example: @Mock Dependency dep; @InjectMocks TestedClass tested; @BeforeEach void setup() { MockitoAnnotations.openMocks(this); } Mockito creates 'dep' mock and injects it into 'tested'.
Result
The tested class is ready with all mocks injected, reducing boilerplate code.
Understanding that @InjectMocks automates both creation and injection simplifies test setup significantly.
5
IntermediateInjection Strategies of @InjectMocks
🤔Before reading on: do you think @InjectMocks uses only constructors to inject mocks? Commit to your answer.
Concept: @InjectMocks tries constructor injection first, then setter methods, then field injection to inject mocks.
When creating the tested class, @InjectMocks: 1. Looks for constructors matching mocks. 2. If none, uses setters to inject mocks. 3. If no setters, injects mocks directly into fields. This flexible approach works with many class designs.
Result
Mocks get injected correctly even if the class uses different ways to receive dependencies.
Knowing the injection order helps debug injection issues and design testable classes.
6
AdvancedLimitations and Pitfalls of @InjectMocks
🤔Before reading on: do you think @InjectMocks can inject mocks into private final fields? Commit to your answer.
Concept: @InjectMocks cannot inject mocks into private final fields or when multiple constructors cause ambiguity.
If the tested class has private final fields without setters or ambiguous constructors, @InjectMocks fails silently or throws errors. Also, it does not create mocks; you must annotate dependencies with @Mock or @Spy.
Result
Injection may silently fail, causing NullPointerExceptions during tests if not noticed.
Understanding these limits prevents confusing test failures and guides better class design for testability.
7
ExpertHow @InjectMocks Works Internally
🤔Before reading on: do you think @InjectMocks uses reflection to inject mocks? Commit to your answer.
Concept: @InjectMocks uses Java reflection to instantiate the tested class and inject mocks via constructor, setters, or fields at runtime.
Mockito scans the test class for @Mock/@Spy fields, creates mocks, then finds the tested class annotated with @InjectMocks. It uses reflection to: - Find suitable constructor and call it with mocks. - If no constructor matches, find setters and call them. - If no setters, set fields directly, even if private (using setAccessible). This dynamic approach allows flexible injection without manual code.
Result
Mocks are injected automatically at runtime without explicit code, making tests concise.
Knowing reflection is behind @InjectMocks explains why it can inject private fields and why some injection failures happen due to constructor ambiguity.
Under the Hood
@InjectMocks works by scanning the test class for mocks and the class under test. It uses Java reflection to instantiate the tested class by matching constructor parameters with mocks. If no suitable constructor is found, it tries setter methods, then directly sets fields, bypassing access modifiers. This process happens at runtime before tests run, automating dependency injection without manual wiring.
Why designed this way?
Mockito designed @InjectMocks to reduce boilerplate and errors in test setup. Reflection allows injecting dependencies even into private fields, supporting legacy code without requiring changes. The flexible injection order (constructor, setter, field) covers many coding styles. Alternatives like manual injection were too verbose and error-prone, so this design balances ease of use with compatibility.
┌─────────────────────────────┐
│ Test Class with @Mock fields│
│ and @InjectMocks field      │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Mockito Test Runner          │
│ - Creates mocks             │
│ - Finds tested class        │
│ - Uses reflection:          │
│   • Constructor injection  │
│   • Setter injection       │
│   • Field injection        │
└─────────────┬───────────────┘
              │
              ▼
┌─────────────────────────────┐
│ Tested Class instance with   │
│ mocks injected automatically│
└─────────────────────────────┘
Myth Busters - 4 Common Misconceptions
Quick: Does @InjectMocks create mocks automatically for dependencies? Commit yes or no.
Common Belief:@InjectMocks automatically creates mocks for all dependencies of the tested class.
Tap to reveal reality
Reality:@InjectMocks only creates the tested class instance and injects mocks you explicitly create with @Mock or @Spy annotations.
Why it matters:Assuming it creates mocks leads to NullPointerExceptions because dependencies are null if not mocked manually.
Quick: Can @InjectMocks inject mocks into private final fields? Commit yes or no.
Common Belief:@InjectMocks can inject mocks into any field, including private final fields.
Tap to reveal reality
Reality:@InjectMocks cannot inject into private final fields because they cannot be modified after construction.
Why it matters:Tests may silently fail or throw errors if dependencies are private final and not injected, causing confusion.
Quick: Does @InjectMocks always use constructor injection first? Commit yes or no.
Common Belief:@InjectMocks always uses constructor injection to inject mocks.
Tap to reveal reality
Reality:@InjectMocks tries constructor injection first but falls back to setter or field injection if no matching constructor is found.
Why it matters:Knowing this helps debug injection failures and design classes that work well with @InjectMocks.
Quick: Is @InjectMocks suitable for integration tests? Commit yes or no.
Common Belief:@InjectMocks is suitable for all types of tests, including integration tests.
Tap to reveal reality
Reality:@InjectMocks is designed for unit tests to inject mocks; integration tests usually require real dependencies or different setup.
Why it matters:Using @InjectMocks in integration tests can hide real issues and give false confidence.
Expert Zone
1
When multiple constructors exist, @InjectMocks picks the one with the most parameters that can be satisfied by mocks, which can cause unexpected injection if not designed carefully.
2
Field injection by @InjectMocks uses reflection and setAccessible(true), which can break encapsulation and cause issues with security managers or future Java versions.
3
@InjectMocks does not reset mocks between tests; you must manage mock state manually or use proper test lifecycle annotations to avoid test interference.
When NOT to use
@InjectMocks is not suitable when you want full control over object creation or when testing classes with complex initialization logic. In such cases, manual injection or dependency injection frameworks (like Spring) are better. Also, avoid using it in integration or system tests where real dependencies are needed.
Production Patterns
In professional projects, @InjectMocks is used to quickly set up unit tests for service classes with multiple dependencies. Teams combine it with @Mock and @Spy to isolate behavior and verify interactions. It is common to use it with MockitoExtension in JUnit 5 for automatic mock initialization. Complex classes may require manual injection to handle special cases.
Connections
Dependency Injection (DI)
@InjectMocks automates dependency injection in tests, similar to how DI frameworks inject dependencies in production code.
Understanding DI principles helps grasp why @InjectMocks simplifies wiring dependencies and why testability improves with good DI design.
Reflection in Java
@InjectMocks uses Java reflection to instantiate classes and inject mocks dynamically at runtime.
Knowing reflection explains how private fields can be injected and why some injection failures occur due to constructor ambiguity.
Mock Objects in Software Testing
@InjectMocks works closely with mocks to isolate the class under test by injecting fake dependencies.
Understanding mocks clarifies why @InjectMocks requires explicit mock creation and how it helps focus tests on the tested class.
Common Pitfalls
#1Forgetting to annotate dependencies with @Mock causes null injections.
Wrong approach:@InjectMocks TestedClass tested; @BeforeEach void setup() { MockitoAnnotations.openMocks(this); } // No @Mock annotations for dependencies
Correct approach:@Mock Dependency dep; @InjectMocks TestedClass tested; @BeforeEach void setup() { MockitoAnnotations.openMocks(this); }
Root cause:Assuming @InjectMocks creates mocks automatically instead of requiring explicit @Mock annotations.
#2Using @InjectMocks with private final fields without setters leads to injection failure.
Wrong approach:class TestedClass { private final Dependency dep; public TestedClass() { this.dep = null; } } @InjectMocks TestedClass tested; @Mock Dependency dep;
Correct approach:class TestedClass { private final Dependency dep; public TestedClass(Dependency dep) { this.dep = dep; } } @InjectMocks TestedClass tested; @Mock Dependency dep;
Root cause:Final fields must be set via constructor; no setter or field injection possible.
#3Not initializing mocks before tests causes NullPointerExceptions.
Wrong approach:@Mock Dependency dep; @InjectMocks TestedClass tested; @Test void test() { // No MockitoAnnotations.openMocks(this) call tested.method(); }
Correct approach:@Mock Dependency dep; @InjectMocks TestedClass tested; @BeforeEach void setup() { MockitoAnnotations.openMocks(this); } @Test void test() { tested.method(); }
Root cause:Mocks must be initialized before use; forgetting setup causes null mocks.
Key Takeaways
@InjectMocks automates creating the tested class and injecting mocks, reducing boilerplate in unit tests.
It requires explicit @Mock or @Spy annotations for dependencies; it does not create mocks by itself.
Injection tries constructor first, then setters, then fields, which helps with different class designs but can cause ambiguity.
It uses reflection internally, allowing injection into private fields but not into private final fields without constructors.
Understanding its limits and proper use improves test reliability and helps design testable code.

Practice

(1/5)
1. What is the primary purpose of the @InjectMocks annotation in JUnit testing?
easy
A. To spy on real objects without mocking
B. To create the class under test and inject mock dependencies automatically
C. To create mock objects without injecting them
D. To run tests in parallel threads

Solution

  1. Step 1: Understand the role of @InjectMocks

    @InjectMocks creates an instance of the class under test and injects mocks into it automatically.
  2. Step 2: Compare with other annotations

    @Mock creates mock objects, but does not inject them. @Spy wraps real objects. @InjectMocks handles injection.
  3. Final Answer:

    To create the class under test and inject mock dependencies automatically -> Option B
  4. Quick Check:

    @InjectMocks = auto-inject mocks [OK]
Hint: Remember: @InjectMocks builds and injects mocks automatically [OK]
Common Mistakes:
  • Confusing @InjectMocks with @Mock
  • Thinking @InjectMocks creates mocks instead of injecting
  • Assuming @InjectMocks runs tests or manages threads
2. Which of the following is the correct way to declare a field with @InjectMocks in a JUnit 5 test class?
easy
A. @InjectMocks private Service service;
B. @InjectMocks Service service = new Service();
C. @InjectMocks private Service service = new Service();
D. @InjectMocks Service service;

Solution

  1. Step 1: Check field declaration syntax

    Fields with @InjectMocks should be private and declared without manual instantiation.
  2. Step 2: Identify correct syntax

    @InjectMocks private Service service; declares a private field with @InjectMocks without manual instantiation, letting the framework create it.
  3. Final Answer:

    @InjectMocks private Service service; -> Option A
  4. Quick Check:

    Private field + no manual new = correct [OK]
Hint: Use private fields without 'new' for @InjectMocks [OK]
Common Mistakes:
  • Manually instantiating the field defeats @InjectMocks purpose
  • Using package-private or public fields without private
  • Missing semicolon or incorrect syntax
3. Given the following test code snippet, what will be the output of service.process() if dependency.doWork() is mocked to return "mocked"?
class Dependency {
    String doWork() { return "real"; }
}

class Service {
    Dependency dependency;
    String process() { return dependency.doWork(); }
}

@InjectMocks
Service service;

@Mock
Dependency dependency;

@BeforeEach
void setup() {
    MockitoAnnotations.openMocks(this);
    when(dependency.doWork()).thenReturn("mocked");
}

@Test
void testProcess() {
    System.out.println(service.process());
}
medium
A. Compilation error
B. "real"
C. NullPointerException
D. "mocked"

Solution

  1. Step 1: Understand @InjectMocks and @Mock interaction

    @InjectMocks creates Service and injects the mocked Dependency instance into it.
  2. Step 2: Analyze method call and mock behavior

    dependency.doWork() is mocked to return "mocked", so service.process() returns "mocked".
  3. Final Answer:

    "mocked" -> Option D
  4. Quick Check:

    Mocked method returns "mocked" [OK]
Hint: Mocks override real methods; expect mocked return values [OK]
Common Mistakes:
  • Expecting real method output instead of mocked
  • Forgetting to initialize mocks with openMocks
  • Assuming dependency is null causing NullPointerException
4. Consider the following test setup:
@InjectMocks
Service service;

@Mock
Dependency dependency;

@BeforeEach
void setup() {
    MockitoAnnotations.openMocks(this);
}

@Test
void test() {
    System.out.println(service.process());
}

When running the test, a NullPointerException occurs at service.process(). What is the most likely cause?
medium
A. The @InjectMocks annotation is applied to the wrong class
B. The @Mock annotation is missing
C. The dependency field in Service is not initialized or injected
D. MockitoAnnotations.openMocks(this) was not called

Solution

  1. Step 1: Identify cause of NullPointerException

    NullPointerException at service.process() means dependency inside Service is null.
  2. Step 2: Check injection of mocks

    @InjectMocks should inject mocks into Service fields, but if Service's dependency field is not properly declared or missing setter, injection fails.
  3. Final Answer:

    The dependency field in Service is not initialized or injected -> Option C
  4. Quick Check:

    NullPointerException = missing injection [OK]
Hint: NullPointerException often means mock not injected properly [OK]
Common Mistakes:
  • Assuming missing @Mock causes NPE (it causes different errors)
  • Thinking openMocks call is missing when it is present
  • Confusing @InjectMocks placement with injection failure
5. You have a class OrderService that depends on PaymentService and InventoryService. You want to write a JUnit test using @InjectMocks to inject mocks of both dependencies. Which setup correctly uses @InjectMocks and @Mock to achieve this?
hard
A. @InjectMocks OrderService orderService; @Mock PaymentService paymentService; @Mock InventoryService inventoryService;
B. @Mock OrderService orderService; @InjectMocks PaymentService paymentService; @InjectMocks InventoryService inventoryService;
C. @InjectMocks OrderService orderService = new OrderService(); @Mock PaymentService paymentService; @Mock InventoryService inventoryService;
D. @Mock OrderService orderService; @Mock PaymentService paymentService; @Mock InventoryService inventoryService;

Solution

  1. Step 1: Identify the class under test

    OrderService is the class under test, so it should be annotated with @InjectMocks.
  2. Step 2: Identify dependencies to mock

    PaymentService and InventoryService are dependencies, so they should be annotated with @Mock.
  3. Step 3: Check for manual instantiation

    OrderService should not be manually instantiated when using @InjectMocks to allow automatic injection.
  4. Final Answer:

    @InjectMocks OrderService orderService; @Mock PaymentService paymentService; @Mock InventoryService inventoryService; -> Option A
  5. Quick Check:

    Class under test @InjectMocks + dependencies @Mock [OK]
Hint: InjectMocks on class under test; Mocks on dependencies [OK]
Common Mistakes:
  • Annotating dependencies with @InjectMocks instead of @Mock
  • Manually instantiating class under test with @InjectMocks
  • Annotating class under test with @Mock instead of @InjectMocks
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard