javaunit-testingmockitoquarkuscdi

Inject a list of mocks during testing in Quarkus


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?


Solution

  • 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.