I have a bean like this:
@ApplicationScoped
public class MyService {
@Inject
@All
List<MyDataProvider> dataProviders;
public List<String> getAllData() {
var data = new ArrayList<String>();
for (var provider : dataProviders) {
data.add(provider.getData());
}
return data;
}
}
And here is the MyDataProvider
interface:
public interface MyDataProvider {
String getData();
}
Let's say, there are tens of beans, implementing the MyDataProvider
interface.
I'd like to replace them all with a specific set of mocks within a unit test and I struggle to find a proper way to do this.
I can mock particular implementations of MyDataProvider
using the @InjectMock
or QuarkusMock.installMockForInstance()
, I just don't know how to prevent injection of the rest non-mocked beans during the test (I need only a couple of mocks to test basic functionality).
So, is there a way to completely override the set of beans being injected in such a field during testing?
The solution I ended up with looks like this.
I replaced @All List<MyDataProvider>
with Instance<MyDataProvider>
and mocked its iterator()
method:
@ApplicationScoped
public class MyService {
@Inject
Instance<MyDataProvider> dataProviders;
public List<String> getAllData() {
var data = new ArrayList<String>();
for (var provider : dataProviders) {
data.add(provider.getData());
}
return data;
}
}
@QuarkusTest
class MyServiceTest {
@Mock
Instance<MyDataProvider> dataProviders;
@InjectMocks
MyService myService;
@BeforeEach
void setUp() {
MockitoAnnotations.openMocks(this);
}
@Test
void doTest() {
List<MyDataProvider> mocks = ... // initialize a list of MyDataProvider mocks
Mockito.when(dataProviders.iterator()).thenReturn(mocks.iterator());
// now myService.dataProviders will act as if it only contains mocked beans
}
}
I don't find it particularly nice, I think there should be a more straightforward way to do this, but at least it works.