tomee-users mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Xavier Dury <kal...@hotmail.com>
Subject Re: ApplicationComposer and qualified mocks
Date Wed, 05 Apr 2017 11:28:38 GMT
Hi Romain

> From: Romain Manni-Bucau <rmannibucau@gmail.com>
>     
> Hi Xavier,
> 
> 2017-04-05 12:22 GMT+02:00 Xavier Dury <kalgon@hotmail.com>:
> 
>> Hi,
>>
>> When using ApplicationComposer, I can declare mocks in my test classes
>> like that:
>>
>> @Mock
>> MyDependency myDependency;
>>
>> @MockInjector
>> public Class<?> mockInjector() { return MockitoInjector.class; }
>>
>> But that does not seem to work with (un@Named) qualified mocks:
> 
> Hmm, MockitoInjector has no link with CDI, it is for EJB injections (which
> are not using CDI/@Inject)
>
>> @Mock
>> @MyQualifier
>> MyDependency myDependency;
> 
> This looks like a cdi injection but @Inject is missing

No, this is no CDI injection, it is the declaration of the qualified mock in my test class.
That field is set by MockitoAnnotations.initMocks() (through MockInjector).

>> Of course, I can still make a producer for the qualified mock like this:
>>
>> @Produces
>> @MyQualifier
>> MyDependency myDependency() { return Mockito.mock(MyDependency.class); }
>>
>> But I wanted to know if that was the only way to do it because, now, I
>> have to programmatically create the mock instead of declaring it with @Mock.
> 
> The openejb-mockito extension only supports @Default and @Any qualifiers (
> https://github.com/apache/tomee/blob/master/utils/openejb-mockito/src/main/java/org/apache/openejb/mockito/MockitoExtension.java)
> but no real blocker to support another one. The only issue is to define how
> to select an instance based on a qualifier then.
> 
> Note: @Named is not a "real" qualifier so you actually used @Default I think

When MockRegistry is looping on all the fields of the TestInstance to gather 
the mocks created by MockitoAnnotations.initMocks(), it should also keep all
qualifiers declared on the field.

Of course, this is not trivial with stereotypes and qualifiers added at runtime
through BeforeBeanDiscover.addQualifier() (but all annotations could be kept and
filtered in the MockitoExtension which has access to the BeanManager).

MockitoExtension would then need to register a bean for each mock with the
correct type AND qualifiers.

Here is a full example of what I want to do:

@RunWith(ApplicationComposer.class)
@Classes(cdi = true, innerClassesAsBean = true)
public class MyTest {
    
    public static class MyBean {
        
        @Inject
        @MyQualifier
        public MyInterface myInterface;
        
        public void printMessage() {
            System.out.println(myInterface.getMessage());
        }
    }
    
    public interface MyInterface {
        String getMessage();
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface MyQualifier {}
    
    @Inject
    private MyBean myBean;
    
    @Mock
    @MyQualifier
    private MyInterface myInterface;
    
    @Test
    public void test() {
        Mockito.doReturn("Hello world!").when(myInterface).getMessage();
        myBean.printMessage();
        Mockito.verify(myInterface).getMessage();
    }
    
    @MockInjector
    public Class<? extends FallbackPropertyInjector> mockInjector() {
        return MockitoInjector.class;
    }
}

Currently, that does not work because MyBean.myInterface won't be resolved.

My current workaround is:

@RunWith(ApplicationComposer.class)
@Classes(cdi = true, innerClassesAsBean = true)
public class MyTest {
    
    public static class MockProducer {
        
        @Produces
        @MyQualifier
        static MyInterface myInterface = Mockito.mock(MyInterface.class);
    }
    
    public static class MyBean {
        
        @Inject
        @MyQualifier
        public MyInterface myInterface;
        
        public void printMessage() {
            System.out.println(myInterface.getMessage());
        }
    }
    
    public interface MyInterface {
        String getMessage();
    }
    
    @Retention(RetentionPolicy.RUNTIME)
    @Qualifier
    public @interface MyQualifier {}
    
    @Inject
    private MyBean myBean;
    
    @Inject
    @MyQualifier
    private MyInterface myInterface;
    
    @Test
    public void test() {
        Mockito.doReturn("Hello world!").when(myInterface).getMessage();
        myBean.printMessage();
        Mockito.verify(myInterface).getMessage();
    }    
}
Mime
View raw message