I have a Helidon application and I would like to test (part of) it.
My test is annotated with @HelidonTest
, and now I would like to replace one bean by a mock (and configure this mock, use all other beans as they are found, but with the mock injected).
I did figured out how to:
@Priority(1)
and @Alternative
and supply it by annotating the test with @AddBean(MyBeanTestImpl.class)
.
mock(MyBean.class)
: By creating a producer method and annotate it with @Produces
:
@Alternative
it is simply ignored.@Priority(1)
, because this annotation can only be applied to types and parameters.Any idea how I can replace one bean by a mock?
I tried setter injection to manually inject mock beans.
Class under test
@ApplicationScoped
public class SomeService {
private ExternalService externalService;
@Inject
public void setExternalService(ExternalService externalService) {
this.externalService = externalService;
}
public String doSomething() {
return externalService.getData();
}
}
Test Class
@HelidonTest
class SomeServiceTest {
@Inject
private SomeService someService;
private ExternalService externalService;
@BeforeEach
void setUp() {
externalService = Mockito.mock(ExternalService.class);
someService.setExternalService(externalService);
}
@Test
void doSomething() {
Mockito.when(externalService.getData())
.thenReturn("Mock data");
String actual = someService.doSomething();
Assertions.assertEquals("Mock data", actual);
}
}
There are also methods to mock a whole bean by mocking the constructor as well. For that, we have to make use of @Observes annotation
@HelidonTest
public abstract class HelidonTestHelper {
private MockedConstruction<ExternalService> mockedConstruction;
void init(@Priority(1) @Observes @Initialized(ApplicationScoped.class) ContainerInitialized containerInitialized) {
mockedConstruction = Mockito.mockConstruction(ExternalService.class);
//mock common beans here. This will be executed once application scope is loaded.
}
void onStop(@Priority(1) @Observes @Destroyed(ApplicationScoped.class) ContainerShutdown containerShutdown) {
//do cleanup here if needed.
mockedConstruction.closeOnDemand();
}
}
Once the above is done, instead of helidon test, you can extend the helper class we created.
class SomeServiceTest extends HelidonTestHelper {
@Inject
private SomeService someService;
@Inject //this will be a mock
private ExternalService externalService;
@Test
void doSomething() {
Mockito.when(externalService.getData())
.thenReturn("Mock data");
String actual = someService.doSomething();
Assertions.assertEquals("Mock data", actual);
}
}