Here’s the revised version using @ExtendWith
and @InjectMocks
for CDI-style mocking:
Testing Jakarta EE REST APIs with Mockito and JUnit 5
Discover how to test Jakarta EE 10 APIs without a server using Mockito’s dependency injection and JUnit 5 extensions.
1. Maven Dependencies
Add these testing frameworks to your pom.xml
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
xml<code><dependencies> <em><!-- Jakarta EE 10 API --></em> <dependency> <groupId>jakarta.platform</groupId> <artifactId>jakarta.jakartaee-api</artifactId> <version>10.0.0</version> <scope>provided</scope> </dependency> <em><!-- Testing --></em> <dependency> <groupId>org.junit.jupiter</groupId> <artifactId>junit-jupiter</artifactId> <version>5.9.2</version> <scope>test</scope> </dependency> <dependency> <groupId>org.mockito</groupId> <artifactId>mockito-junit-jupiter</artifactId> <version>5.4.0</version> <scope>test</scope> </dependency> </dependencies> |
2. REST Resource with CDI
A Jakarta EE resource using @Inject
for service layer dependency:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
java<code>import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import jakarta.inject.Inject; @Path("/greet") public class GreetingResource { @Inject private GreetingService service; @GET public String greet() { return service.generate(); } } |
3. Test Class with Mockito Injection
Using @ExtendWith
and @InjectMocks
to mock CDI dependencies:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
java<code>import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.Mockito.*; @ExtendWith(MockitoExtension.class) public class GreetingResourceTest { @Mock private GreetingService mockService; @InjectMocks private GreetingResource resource; @Test void testGreet() { <em>// Configure mock</em> when(mockService.generate()).thenReturn("Mocked greeting"); <em>// Test resource method directly</em> String result = resource.greet(); <em>// Verify</em> assertEquals("Mocked greeting", result); verify(mockService).generate(); } } |
Key Improvements
- No HTTP Server: Tests business logic directly without JerseyTest
- CDI-Style Mocking:
@InjectMocks
simulates Jakarta EE’s@Inject
behavior - Simplified Setup: Removes Jersey dependencies for pure unit testing
How It Works
@ExtendWith(MockitoExtension.class)
: Enables Mockito’s JUnit 5 integration@Mock
: Creates a mock instance ofGreetingService
@InjectMocks
: Injects mocks into fields annotated with@Inject
- Direct Method Invocation: Tests resource methods without HTTP layer
Testing CDI Components
For full CDI container testing (including interceptors and producers), use CDI Test:
1 2 3 4 5 6 7 |
xml<code><dependency> <groupId>org.jboss.weld</groupId> <artifactId>weld-junit5</artifactId> <version>4.0.3.Final</version> <scope>test</scope> </dependency> |
1 2 3 4 5 6 7 8 9 10 11 |
java<code>@ExtendWith(WeldJunit5Extension.class) class FullCdiTest { @Inject GreetingResource resource; @Test void testCdiContainer() { assertNotNull(resource); } } |
Common Issues & Fixes
Problem: NullPointerException
in @InjectMocks
Solution: Ensure all dependencies are properly mocked with @Mock
Problem: CDI features missing
Solution: Use weld-junit5
for full CDI container testing
Problem: Annotation conflicts
Solution: Avoid mixing @InjectMocks
with real CDI containers
When to Use This Approach
Unit Testing: Isolated service/resource testing
Fast Feedback: No server startup required
Mock Validation: Verify interactions with dependencies
Implementation Notes
- Limited CDI Features:
@InjectMocks
only handles basic injection - No Interceptors: Use CDI Test or Arquillian for advanced scenarios
- Jakarta EE 10: Requires Java 17+ and updated Mockito dependencies
Alternative for REST Endpoints
For HTTP layer testing with dependency injection:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 |
java<code>@ExtendWith(MockitoExtension.class) public class GreetingResourceHttpTest extends JerseyTest { @Mock private GreetingService service; @Override protected Application configure() { <em>// Manual injection workaround</em> return new ResourceConfig() .register(new GreetingResource() {{ this.service = service; }}); } @Test void testHttpEndpoint() { when(service.generate()).thenReturn("HTTP mock"); String response = target("greet").request().get(String.class); assertEquals("HTTP mock", response); } } |