apache / dubbo

The java implementation of Apache Dubbo. An RPC and microservice framework.
https://dubbo.apache.org/
Apache License 2.0
40.47k stars 26.43k forks source link

在 spring boot 中使用 dubbo, 对注解 @DubboReference 依赖, 希望可以提供 @MockBean 的功能 #9116

Open ooooo-youwillsee opened 3 years ago

24kpure commented 3 years ago

Do you mean DubboReference‘s dependencies in unit tests?

ooooo-youwillsee commented 3 years ago

yes

I have one configuration class , for example:

@Configuration
public class XXXConfiguration {

   @DubboReference
   private SomeService someService;

  @Bean
  public AnotherService anotherService() {
   return new AnotherService() {

     public void invoke() {
       someService.invokeSomeMethod();
     }
 }
}

but I can't test , because someService must use register center for Using Spring cloud alibaba

24kpure commented 3 years ago

Why not mock dubboReference? Here is a best practice for reference @stonelion.

class ReferenceBeanProcessor implements BeanPostProcessor, BeanFactoryPostProcessor {

    private ConfigurableListableBeanFactory beanFactory;

    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        return bean;
    }

    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        List<Field> annotatedFields = FieldUtils.getFieldsListWithAnnotation(bean.getClass(), Reference.class);
        annotatedFields.addAll(FieldUtils.getFieldsListWithAnnotation(bean.getClass(), com.alibaba.dubbo.config.annotation.Reference.class));
        annotatedFields.addAll(FieldUtils.getFieldsListWithAnnotation(bean.getClass(), DubboReference.class));
        for (Field field : annotatedFields) {
            try {
                Class<?> type = field.getType();
                String mockBeanName = BeanFactoryUtils.transformedBeanName(type.getSimpleName());
                if (!beanFactory.containsBean(mockBeanName)) {
                    beanFactory.registerSingleton(mockBeanName, Mockito.mock(type));
                }

                boolean accessible = field.isAccessible();
                field.setAccessible(true);
                field.set(bean, beanFactory.getBean(type));
                field.setAccessible(accessible);
            } catch (IllegalAccessException e) {
            }
        }
        return bean;
    }
}
ooooo-youwillsee commented 2 years ago

The following is my code

@Slf4j
@SpringBootApplication
public class DubboConsumerApplication {

    @DubboReference
    private UserService userService;

    public static void main(String[] args) {
        SpringApplication.run(DubboConsumerApplication.class, args);
    }

    @Bean
    public ApplicationRunner testApplicationRunner() {
        return __ -> {
            String username = userService.getUsernameById(1L);
            log.info("username: {}", username);
        };
    }
}
@SpringBootTest
class DubboConsumerApplicationTest {

    @MockBean
    private UserService userService;

    @Test
    public void testDubboReferenceMockBean() {
        when(userService.getUsernameById(any())).thenReturn("mock username");

        String username1 = userService.getUsernameById(1L);
        assertEquals("mock username", username1);

        String username2 = userService.getUsernameById(1L);
        assertEquals("mock username", username2);
    }
}

bootstrap.yml

spring:
  application:
    name: demo-spring-cloud-dubbo-consumer
dubbo:
  protocols:
    dubbo:
      name: dubbo
      port: -1
  registry:
    address: N/A
#    address: 224.5.6.7:2222  # No matter what is configured, the error is reported
  scan:
    base-packages: com.ooooo
  consumer:
    check: false

dependencies

mavenBom "com.alibaba.cloud:spring-cloud-alibaba-dependencies:2.2.6.RELEASE"
mavenBom "org.springframework.cloud:spring-cloud-dependencies:Hoxton.SR10"
//=========
    api('org.springframework.boot:spring-boot-starter-web')
    api('com.alibaba.cloud:spring-cloud-starter-dubbo')
    api('com.alibaba.cloud:spring-cloud-starter-alibaba-nacos-discovery')

You can find the code here

vergilyn commented 2 years ago

i have the same need. the simple @MockBean annotation mock @dubboReference is not available. see: https://github.com/apache/dubbo-spring-boot-project/issues/802

ghxiaoym commented 1 year ago

Testing is not important.Either you or your code can run is ok