I have a class which stores data, and needs access to an external service. How do I configure this class so that I can instantiate it with data, while still allowing the ability to inject a mock of the service in tests?
@Service
@Scope("prototype")
final class Adapter {
@Autowired private AdapterService adapterService;
private final Options s;
@Autowired
Adapter(@NotNull Options options) {
this.options = options;
}
}
@Test
void adapter() {
// How do I inject mock(AdapterService.class)?
Adapter adapter = applicationContext.getBean(Adapter.class, options);
}
Some hacky workarounds I've played with:
- TestOnly Constructor
- TestOnly Setter to override adapterService
- Setting the adapterService property via reflection
Please tell me that these aren't the only options, and that Spring provides support for this common use-case!
I suppose you're using the tests without spring (plain unit tests) with JUnit or something. In this case, I suggest moving from the field injection (that you use to inject the service) to the constructor injection. Your class will look like this:
I see that the
Adapteris a prototype but Spring will still be able to inject a singleton instance of theAdapterServiceas long as it's also defined by Spring (it is a bean by itself).Now in a Unit test you will create an
Adapterclass and can pass now as many mocks as you like: