https://github.com/exabrial/mockito-object-injection
Mockito Object Injection for JUnit5. Inject Strings and other Objects directly into Mocks without needing setters or constructor injection.
https://github.com/exabrial/mockito-object-injection
cdi dependency-injection java java-ee junit junit-extension junit5 junit5-framework mocking mockito spring spring-boot springboot testing
Last synced: 10 days ago
JSON representation
Mockito Object Injection for JUnit5. Inject Strings and other Objects directly into Mocks without needing setters or constructor injection.
- Host: GitHub
- URL: https://github.com/exabrial/mockito-object-injection
- Owner: exabrial
- License: apache-2.0
- Created: 2018-09-11T21:37:47.000Z (over 7 years ago)
- Default Branch: master
- Last Pushed: 2025-02-01T21:03:52.000Z (12 months ago)
- Last Synced: 2025-07-17T19:59:18.130Z (6 months ago)
- Topics: cdi, dependency-injection, java, java-ee, junit, junit-extension, junit5, junit5-framework, mocking, mockito, spring, spring-boot, springboot, testing
- Language: Java
- Homepage:
- Size: 48.8 KB
- Stars: 8
- Watchers: 3
- Forks: 4
- Open Issues: 0
-
Metadata Files:
- Readme: README.md
- License: LICENSE
Awesome Lists containing this project
README
# Mockito Object Injection
## Preamble
* Mock testing leads to highly focused tests where every variable is controlled.
* Dependency Injection + well structured programs + Mock testing = super clean codebase.
The problem is, how does one Mock a String, Boolean, or other final type if those types are being Injected?
## Summary
This Junit Extension allows you to inject Strings (or any other object) into your `@InjectMocks` targets [objects under test] without booting a Spring, Weld, CDI, Arquillian, EJB, or other container. It's super lightweight, over 100,000x faster than booting Arquillian, and easy to use.
## Example Problem
Take this Spring Controller (or if you're using the far superior and modern CDI framework, think `@AppplicationScoped` instead of `@Controller` and `@Inject` instead of `@Autowired`)
```
@Controller
public class MyController {
@Value("securityEnabled")
private Boolean securityEnabled;
@Autowired
private Authenticator auther;
@Autowired
private Logger log;
public void doSomething() {
if (securityEnabled) {
auther.something();
} else {
log.warn("sec disabled");
}
}
}
```
If you wanted to write a _true unit test*_ with no external dependencies, you'd probably want to use Mockito mock your dependencies:
```
@ExtendWith({ MockitoExtension.class })
class MyControllerTest {
@InjectMocks
private MyController myController;
@Mock
private Logger log;
@Mock
private Authenticator auther;
@Test
void testDoSomething() throws Exception {
myController.doSomething();
// results in NPE because myController.securityEnabled is null
}
}
```
* Testing a "unit" of code is a unit test. In Java, typically a class is the smallest unit of code. A static funciton can also be considered a unit of code, but static functions should not be tested using Mock testing for reasons beyond the scope of this document. See: http://misko.hevery.com/2008/12/15/static-methods-are-death-to-testability
## Example Solution
This JUnit5 extension allows you to arbitrarily set any field on your `@InjectMocks` [class under test] target. The injections happen _very late_; they happen when you call any non-private method on the class under test.
```
import com.github.exabrial.junit5.injectmap.InjectionMap;
import com.github.exabrial.junit5.injectmap.InjectMapExtension;
@TestInstance(Lifecycle.PER_CLASS)
@ExtendWith({ MockitoExtension.class, InjectExtension.class })
class MyControllerTest {
@InjectMocks
private MyController myController;
@Mock
private Logger log;
@Mock
private Authenticator auther;
@InjectionSource
private Boolean securityEnabled;
@Test
void testDoSomething_secEnabled() throws Exception {
securityEnabled = Boolean.TRUE;
myController.doSomething();
// wahoo no NPE! Test the "if then" half of the branch
}
@Test
void testDoSomething_secDisabled() throws Exception {
securityEnabled = Boolean.FALSE;
myController.doSomething();
// wahoo no NPE! Test the "if else" half of branch
}
}
```
## @PostConstruct invocation
CDI and SpringFramework allow the use of `@PostConstruct`. This is like a constructor, except the method annotated will be invoked _after_ dependency injection is complete. This extension can be commanded to invoke the method annotated with `@PostConstruct` like so:
```
@ApplicationScoped
public class MyController {
@Inject
private Logger log;
@PostConstruct
private void postConstruct() {
log.info("initializing myController...");
... some initialization code
}
}
```
```
@TestInstance(Lifecycle.PER_CLASS)
@ExtendWith({ MockitoExtension.class, InjectExtension.class })
class MyControllerTest {
@InjectMocks
@InvokePostConstruct
// The postConstruct on this controller will be invoked
private MyController myController;
@Test
void testSometing()
```
Ref: https://docs.oracle.com/javaee/7/api/javax/annotation/PostConstruct.html
## Enabling/Disabling Injection Behavior
The InjectExtension provides methods to turn on and off the behavior as well as query the status of injection.
```
InjectExtension.enable();
InjectExtension.bypass();
InjectExtension.status(); // returns true if enabled
```
It's recommended that if you're using the above APIs that you reset the Injector status between tests.
```
@AfterEach
void afterEach() {
InjectExtension.enable();
}
```
## License
All files are licensed Apache Source License 2.0. Please consider contributing any improvements you make back to the project.
## Usage
Maven Coordinates:
```
org.junit.jupiter
junit-jupiter-api
5.8.2
test
org.mockito
mockito-core
4.6.1
test
com.github.exabrial
mockito-object-injection
2.3.0
test
```
The final note is that it should extraordinarily obvious that multithreading on the same test instances will cause problems. Set your forking policies accordingly to avoid race conditions.