Soul-单测小结

image-20210206195040098

常用 UT

Properties UT

public final class NacosPropertiesTest extends AbstractConfigurationTest {

  @Test
  public void testNacosPropertiesDefault() {
    load(NacosPropertiesTest.NacosPropertiesConfiguration.class);
    NacosProperties nacosProperties = getContext().getBean(NacosProperties.class);
    assertNull(nacosProperties.getUrl());
    assertNull(nacosProperties.getNamespace());
    assertNull(nacosProperties.getAcm());
  }

  @Test
  public void testNacosPropertiesSpecified() {
    final String url = "localhost:8848";
    final String namespace = "1c10d748-af86-43b9-8265-75f487d20c6c";
    NacosProperties.NacosACMProperties acm = new NacosProperties.NacosACMProperties();
    acm.setEnabled(false);
    acm.setEndpoint("acm.aliyun.com");

    load(NacosPropertiesTest.NacosPropertiesConfiguration.class, "soul.sync.nacos.url=localhost:8848",
         "soul.sync.nacos.namespace=1c10d748-af86-43b9-8265-75f487d20c6c",
         "soul.sync.nacos.acm.enabled=false",
         "soul.sync.nacos.acm.endpoint=acm.aliyun.com");
    NacosProperties nacosProperties = getContext().getBean(NacosProperties.class);
    assertEquals(nacosProperties.getUrl(), url);
    assertEquals(nacosProperties.getNamespace(), namespace);
    assertEquals(nacosProperties.getAcm().isEnabled(), acm.isEnabled());
    assertEquals(nacosProperties.getAcm().getEndpoint(), acm.getEndpoint());
  }

  @Configuration
  @EnableConfigurationProperties(NacosProperties.class)
  static class NacosPropertiesConfiguration {
  }
}

// 抽象类
public abstract class AbstractConfigurationTest {

  private final AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();

  /**
     * Get the current mock context.
     *
     * @return AnnotationConfigApplicationContext
     */
  public AnnotationConfigApplicationContext getContext() {
    return context;
  }

  /**
     * clear context.
     */
  @AfterEach
  public void clear() {
    context.close();
  }

  /**
     * Add properties to Environment and register configuration into spring context.
     *
     * @param configuration the configuration class
     * @param inlinedProperties the config properties
     */
  public void load(final Class<?> configuration, final String... inlinedProperties) {
    load(new Class<?>[]{configuration}, inlinedProperties);
  }

  /**
     * Add properties to Environment and register configuration into spring context.
     *
     * @param configuration the configuration class array
     * @param inlinedProperties the config properties
     */
  public void load(final Class<?>[] configuration, final String... inlinedProperties) {
    TestPropertySourceUtils.addInlinedPropertiesToEnvironment(this.context, inlinedProperties);
    this.context.register(configuration);
    this.context.refresh();
  }
}

Controller UT

@RunWith(MockitoJUnitRunner.class)
public final class ConfigControllerTest {

    private MockMvc mockMvc;

    @InjectMocks
    private ConfigController configController;

    @Mock
    private HttpLongPollingDataChangedListener mockLongPollingListener;

    @Before
    public void setUp() {
        this.mockMvc = MockMvcBuilders.standaloneSetup(configController).build();
    }

    @Test
    public void testFetchConfigs() throws Exception {
        final ConfigData<?> configData = new ConfigData<>("md5-value1", 0L, Collections.emptyList());         
       doReturn(configData).when(mockLongPollingListener).fetchConfig(ConfigGroupEnum.APP_AUTH);

        final MockHttpServletResponse response = mockMvc.perform(get("/configs/fetch")
                .param("groupKeys", new String[]{ConfigGroupEnum.APP_AUTH.toString()})
                .accept(MediaType.APPLICATION_JSON))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.message", is(SoulResultMessage.SUCCESS)))
                .andExpect(jsonPath("$.data['APP_AUTH'].md5", is("md5-value1")))
                .andReturn().getResponse();

        // Verify the results
        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
    }

    @Test
    public void testListener() throws Exception {
        // Run the test
        final MockHttpServletResponse response = mockMvc.perform(post("/configs/listener")
                .accept(MediaType.APPLICATION_JSON))
                .andReturn().getResponse();

        // Verify the results
        assertThat(response.getStatus()).isEqualTo(HttpStatus.OK.value());
        verify(mockLongPollingListener).doLongPolling(any(HttpServletRequest.class), any(HttpServletResponse.class));
    }
}

SpringBoot-starter UT

@RunWith(SpringRunner.class)
@SpringBootTest(
        classes = {
                SoulAlibabaDubboClientConfiguration.class,
                SoulAlibabaDubboClientConfigurationTest.class
        },
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        properties = {
                "soul.dubbo.adminUrl=http://localhost:9095",
                "soul.dubbo.contextPath=/dubbo",
                "soul.dubbo.appName=dubbo"
        })
@EnableAutoConfiguration
public final class SoulAlibabaDubboClientConfigurationTest {

    @Autowired
    private DubboConfig dubboConfig;

    @Test
    public void testDubboConfig() {
        assertThat(dubboConfig.getAppName(), is("dubbo"));
        assertThat(dubboConfig.getContextPath(), is("/dubbo"));
        assertThat(dubboConfig.getAdminUrl(), is("http://localhost:9095"));
    }
}

配置类 Starter

@ConditionalOnClass({LoadBalancerClient.class, RibbonAutoConfiguration.class, DispatcherHandler.class})
@AutoConfigureAfter(RibbonAutoConfiguration.class)
@ConditionalOnBean(LoadBalancerClient.class)
@Configuration
public class SpringCloudPluginConfiguration {

    /**
     * init springCloud plugin.
     *
     * @param loadBalancerClient the load balancer client
     * @return {@linkplain SpringCloudPlugin}
     */
    @Bean
    public SoulPlugin springCloudPlugin(final ObjectProvider<LoadBalancerClient> loadBalancerClient) {
        return new SpringCloudPlugin(loadBalancerClient.getIfAvailable());
    }
}


public class SpringCloudPluginConfigurationTest {

    @Test
    public void testSpringCloudPlugin() {
        new ApplicationContextRunner()
            .withConfiguration(
                AutoConfigurations.of(
                        RibbonAutoConfiguration.class,
                        DispatcherHandler.class,
                        RibbonClientConfiguration.class,
                        SpringCloudPluginConfiguration.class
                ))
            .withPropertyValues(
                "debug=true",
                "spring.main.banner-mode=off",
                "ribbon.client.name=test")
            .run(
                context -> {
                    assertThat(context).hasSingleBean(LoadBalancerClient.class);
                    assertThat(context).hasSingleBean(RibbonAutoConfiguration.class);
                    assertThat(context).hasSingleBean(DispatcherHandler.class);
                    assertThat(context).getBean(LoadBalancerClient.class).isInstanceOf(RibbonLoadBalancerClient.class);
                    SoulPlugin plugin = context.getBean(SoulPlugin.class);
                    assertThat(plugin.named()).isEqualTo(PluginEnum.SPRING_CLOUD.getName());
                }
            );
    }
}

一些补充

过滤干扰方法

@RunWith(SpringRunner.class)
@SpringBootTest(
        classes = {
                SoulSpringCloudClientConfiguration.class,
                SoulSpringCloudClientConfigurationTest.class
        },
        webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
        properties = {
                "spring.application.name=spring-cloud-server",
                "soul.springcloud.adminUrl=http://localhost:9095",
                "soul.springcloud.contextPath=spring-cloud-server",
                "soul.springcloud.full=true"
        }
)
@EnableAutoConfiguration
public final class SoulSpringCloudClientConfigurationTest {
    @Autowired
    private SoulSpringCloudConfig soulSpringCloudConfig;

    @BeforeClass
    public static void before() {
        MockedStatic<RegisterUtils> registerUtilsMockedStatic = mockStatic(RegisterUtils.class);
        registerUtilsMockedStatic.when(() -> RegisterUtils.doRegister(any(), any(), any())).thenAnswer((Answer<Void>) invocation -> null);
    }

    @Test
    public void testSoulSpringCloudConfig() {
        assertThat(soulSpringCloudConfig.getContextPath(), is("spring-cloud-server"));
        assertThat(soulSpringCloudConfig.getAdminUrl(), is("http://localhost:9095"));
        Assertions.assertThat(soulSpringCloudConfig.isFull()).isTrue();
    }
}

静态类

public final class RegisterUtilsTest {

    private OkHttpTools okHttpTools;

    private String json;

    private String url;

    @Before
    public void setUp() {
        okHttpTools = mock(OkHttpTools.class);

        Map<String, Object> jsonMap = new HashMap<String, Object>() {
            {
                put("appName", "dubbo");
                put("contextPath", "/dubbo");
                put("path", "/dubbo/findByArrayIdsAndName");
                put("pathDesc", "");
                put("serviceName", "org.dromara.soul.examples.dubbo.api.service.DubboMultiParamService");
                put("ruleName", "/dubbo/findByArrayIdsAndName");
                put("parameterTypes", "[Ljava.lang.Integer;,java.lang.String");
                put("rpcExt", "{\"group\":\"\",\"version\":\"\",\"loadbalance\":\"random\",\"retries\":2,\"timeout\":10000,\"url\":\"\"}");
                put("enabled", true);
            }
        };

        json = JsonUtils.toJson(jsonMap);
        url = "http://localhost:9095/soul-client/dubbo-register";
    }

    @SneakyThrows
    @Test
    public void testDoRegisterWhenThrowException() {
        when(okHttpTools.post(url, json)).thenThrow(IOException.class);

        try (MockedStatic<OkHttpTools> okHttpToolsMockedStatic = mockStatic(OkHttpTools.class)) {
            okHttpToolsMockedStatic.when(OkHttpTools::getInstance).thenReturn(okHttpTools);
            RegisterUtils.doRegister(json, url, RpcTypeEnum.DUBBO);
            verify(okHttpTools, times(1)).post(eq(url), eq(json));
        }
    }
}

批量 Set Get

public abstract class AbstractReflectGetterSetterTest {

    /**
     * A map of default mappers for common objects.
     */
    private static final Map<Class<?>, Object> DEFAULT_MAPPERS;

    static {
        DEFAULT_MAPPERS = new HashMap<>();

        /* Primitives */
        DEFAULT_MAPPERS.put(int.class, 0);
        DEFAULT_MAPPERS.put(double.class, 0.0d);
        DEFAULT_MAPPERS.put(float.class, 0.0f);
        DEFAULT_MAPPERS.put(long.class, 0L);
        DEFAULT_MAPPERS.put(boolean.class, true);
        DEFAULT_MAPPERS.put(short.class, 0);
        DEFAULT_MAPPERS.put(byte.class, 0);
        DEFAULT_MAPPERS.put(char.class, 0);

        DEFAULT_MAPPERS.put(Integer.class, 0);
        DEFAULT_MAPPERS.put(Double.class, 0.0);
        DEFAULT_MAPPERS.put(Float.class, 0.0f);
        DEFAULT_MAPPERS.put(Long.class, 0L);
        DEFAULT_MAPPERS.put(Boolean.class, Boolean.TRUE);
        DEFAULT_MAPPERS.put(Short.class, (short) 0);
        DEFAULT_MAPPERS.put(Byte.class, (byte) 0);
        DEFAULT_MAPPERS.put(Character.class, (char) 0);

        DEFAULT_MAPPERS.put(BigDecimal.class, BigDecimal.ONE);
        DEFAULT_MAPPERS.put(Date.class, new Date());
        DEFAULT_MAPPERS.put(Timestamp.class, new Timestamp(System.currentTimeMillis()));

        /* Collection Types. */
        DEFAULT_MAPPERS.put(Set.class, Collections.emptySet());
        DEFAULT_MAPPERS.put(SortedSet.class, Collections.emptySortedSet());
        DEFAULT_MAPPERS.put(List.class, Collections.emptyList());
        DEFAULT_MAPPERS.put(Map.class, Collections.emptyMap());
        DEFAULT_MAPPERS.put(SortedMap.class, Collections.emptySortedMap());
    }

    protected abstract Class<?> getTargetClass();

    protected Set<String> getExcludeFields() {
        return null;
    }

    /**
     * Test getter and setter method by reflect.
     *
     * @throws Exception maybe throw reflect Exception.
     */
    @Test
    public void testGetAndSet() throws Exception {
        Class<?> clazz = getTargetClass();
        Object target = clazz.getDeclaredConstructor().newInstance();
        Field[] fields = clazz.getDeclaredFields();
        Set<String> excludeFields = getExcludeFields();

        Stream.of(fields)
                .forEach(f -> {
                    if (f.isSynthetic()) {
                        return;
                    }
                    if (excludeFields != null && excludeFields.contains(f.getName())) {
                        return;
                    }
                    try {
                        //get the get and set methods of the field by PropertyDescriptor
                        PropertyDescriptor property = new PropertyDescriptor(f.getName(), clazz);
                        Method getter = property.getReadMethod();
                        Method setter = property.getWriteMethod();

                        final Object setValue = defaultValue(property.getPropertyType());

                        setter.invoke(target, setValue);
                        final Object getValue = getter.invoke(target);
                        assertEquals(setValue, getValue,
                                property.getDisplayName() + " getter / setter do not produce the same result."
                        );
                    } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
                        throw new RuntimeException("", e);
                    }
                });
    }

    @SneakyThrows
    private Object defaultValue(final Class<?> clazz) {
        final Object obj = DEFAULT_MAPPERS.get(clazz);
        if (obj != null) {
            return obj;
        }

        return clazz.newInstance();
    }
}

拦截 HTTP 请求

public final class OkHttpToolsTest {

    @Rule
    public WireMockRule wireMockRule = new WireMockRule(WireMockConfiguration.wireMockConfig().dynamicPort(), false);

    private String url;

    private final String json = "{\"appName\":\"soul\"}";

    @Before
    public void setUpWireMock() {
        wireMockRule.stubFor(post(urlPathEqualTo("/"))
                .willReturn(aResponse()
                        .withHeader(HttpHeaders.CONTENT_TYPE, ContentType.APPLICATION_JSON.toString())
                        .withBody(json)
                        .withStatus(200))
        );
        url = "http://localhost:" + wireMockRule.port();
    }

    @Test
    public void testPostReturnString() throws IOException {
        assertThat(json, is(OkHttpTools.getInstance().post(url, json)));
    }

    @Test
    public void testPostReturnClassT() throws IOException {
        assertThat(GsonUtils.getInstance().fromJson(json, HttpRegisterDTO.class),
                equalTo(OkHttpTools.getInstance().post(url, json, HttpRegisterDTO.class)));
    }

    @Test
    public void testPostReturnMap() throws IOException {
        final Map<String, String> map = new HashMap<>();
        map.put("appName", "soul");
        assertThat(json, is(OkHttpTools.getInstance().post(url, map)));
    }

    @Test
    public void testGetGson() {
        assertThat(OkHttpTools.getInstance().getGson(), notNullValue());
    }
}

单例

public final class UUIDUtilsTest {

    @Test
    public void testGetInstance() {
        UUIDUtils uuidUtils = UUIDUtils.getInstance();
        Assert.assertNotNull(uuidUtils);
    }

    @Test
    public void testGenerateShortUuid() {
        String shortUuid = UUIDUtils.getInstance().generateShortUuid();
        Assert.assertTrue(StringUtils.isNotEmpty(shortUuid));
        Assert.assertEquals(19, shortUuid.length());
    }

    @Test
    public void testConstructor() throws Exception {
        Class<?> uUIDUtilsClass = UUIDUtils.getInstance().getClass();
        Class<?>[] p = {long.class, long.class, long.class};
        Constructor<?> constructor = uUIDUtilsClass.getDeclaredConstructor(p);
        constructor.setAccessible(true);
        try {
            constructor.newInstance(-1L, 10L, 10L);
        } catch (InvocationTargetException ex) {
            Assert.assertTrue(ex.getCause().getMessage().startsWith("worker Id can't be greater than"));
        }

        try {
            constructor.newInstance(10L, -1L, 10L);
        } catch (InvocationTargetException ex) {
            Assert.assertTrue(ex.getCause().getMessage().startsWith("datacenter Id can't be greater than"));
        }
    }

    @Test
    public void testTilNextMillis() throws Exception {
        Class<?> uUIDUtilsClass = UUIDUtils.getInstance().getClass();
        Class<?>[] p = {long.class};
        Method method = uUIDUtilsClass.getDeclaredMethod("tilNextMillis", p);
        method.setAccessible(true);
        long lastTimestamp = System.currentTimeMillis();
        long result = (long) method.invoke(UUIDUtils.getInstance(), lastTimestamp);
        assertThat(result, greaterThan(lastTimestamp));
    }

    @Test
    public void testNextIdException() throws Exception {
        UUIDUtils uuidUtils = UUIDUtils.getInstance();
        Class<?> uUIDUtilsClass = uuidUtils.getClass();
        Field field = uUIDUtilsClass.getDeclaredField("lastTimestamp");
        field.setAccessible(true);
        field.set(uuidUtils, 1617757060000L);

        Method method = uUIDUtilsClass.getDeclaredMethod("nextId");
        method.setAccessible(true);
        try {
            method.invoke(UUIDUtils.getInstance());
        } catch (InvocationTargetException ex) {
            Assert.assertTrue(ex.getCause().getMessage().startsWith("Clock moved backwards."));
        }
    }

    @Test
    public void testNextId() throws Exception {
        UUIDUtils uuidUtils = UUIDUtils.getInstance();
        Class<?> uUIDUtilsClass = uuidUtils.getClass();
        Field field = uUIDUtilsClass.getDeclaredField("lastTimestamp");
        field.setAccessible(true);
        field.set(uuidUtils, System.currentTimeMillis());

        Method method = uUIDUtilsClass.getDeclaredMethod("nextId");
        method.setAccessible(true);
        method.invoke(UUIDUtils.getInstance());
    }

}

SPI 相关

public final class ExtensionLoaderTest {

    @Test
    public void testSPI() {
        JdbcSPI jdbcSPI = ExtensionLoader.getExtensionLoader(JdbcSPI.class).getJoin("mysql");
        assertThat(jdbcSPI.getClass().getName(), is(MysqlSPI.class.getName()));
    }

    /**
     * test SPI has default value case.
     */
    @Test
    public void testSPIGetDefaultJoin() {
        HasDefaultSPI spi = ExtensionLoader.getExtensionLoader(HasDefaultSPI.class).getDefaultJoin();
        assert spi != null;
        assertThat(spi.getClass().getName(), is(SubHasDefaultSPI.class.getName()));
    }

    /**
     * test SPI no default value case.
     */
    @Test
    public void testSPINoDefaultJoin() {
        JdbcSPI jdbcSPI = ExtensionLoader.getExtensionLoader(JdbcSPI.class).getDefaultJoin();
        assertNull(jdbcSPI);
    }

    /**
     * test ExtensionLoader.getJoin() blank name param case.
     */
    @Test
    public void testSPIGetJoinNameIsBlank() {
        try {
            ExtensionLoader.getExtensionLoader(JdbcSPI.class).getJoin("");
            fail();
        } catch (NullPointerException expected) {
            assertThat(expected.getMessage(), containsString("get join name is null"));
        }
    }

    /**
     * test ExtensionLoader.getExtensionLoader() null param case.
     */
    @Test
    public void testGetExtensionLoaderIsNull() {
        try {
            ExtensionLoader.getExtensionLoader(null);
            fail();
        } catch (NullPointerException expected) {
            assertThat(expected.getMessage(), containsString("extension clazz is null"));
        }
    }

    /**
     * test ExtensionLoader.getExtensionLoader() param is not interface case.
     */
    @Test
    public void testGetExtensionLoaderNotInterface() {
        try {
            ExtensionLoader.getExtensionLoader(ExtensionLoaderTest.class);
            fail();
        } catch (IllegalArgumentException expected) {
            assertThat(expected.getMessage(),
                    containsString("extension clazz (class org.dromara.soul.spi.ExtensionLoaderTest) is not interface!"));
        }
    }

    /**
     * test ExtensionLoader.getExtensionLoader() param is not have SPI annotation case.
     */
    @Test
    public void testGetExtensionLoaderNotSpiAnnotation() {
        try {
            ExtensionLoader.getExtensionLoader(NopSPI.class);
            fail();
        } catch (IllegalArgumentException expected) {
            assertThat(expected.getMessage(),
                    containsString("extension clazz (interface org.dromara.soul.spi.fixture.NopSPI) without @interface org.dromara.soul.spi.SPI Annotation"));
        }
    }

    /**
     * test ExtensionLoader.getJoin() param nonentity SPI name case.
     */
    @Test
    public void testGetExtensionLoaderNonentitySPIName() {
        try {
            ExtensionLoader.getExtensionLoader(JdbcSPI.class).getJoin("nonentitySPIName");
            fail();
        } catch (IllegalArgumentException expected) {
            assertThat(expected.getMessage(), containsString("name is error"));
        }
    }

    /**
     * test ExtensionLoader.getJoin() param name not interface subType case.
     */
    @Test
    public void testGetExtensionLoaderSPISubTypeNotMatchInterface() {
        try {
            ExtensionLoader.getExtensionLoader(NotMatchSPI.class).getJoin("subNoJoinSPI");
            fail();
        } catch (IllegalStateException expected) {
            assertThat(expected.getMessage(),
                    containsString("load extension resources error,class org.dromara.soul.spi.fixture.SubNoJoinSPI subtype is not of interface org.dromara.soul.spi.fixture.NotMatchSPI"));
        }
    }

    /**
     * test ExtensionLoader.getJoin() param name no class match case.
     */
    @Test
    public void testGetExtensionLoaderNoClassMatchSPI() {
        try {
            ExtensionLoader.getExtensionLoader(NoClassMatchSPI.class).getJoin("subNoClassMatchSPI");
            fail();
        } catch (IllegalStateException expected) {
            assertThat(expected.getMessage(), containsString("load extension resources error"));
        }
    }

    /**
     * test ExtensionLoader.getJoin() param no join case.
     */
    @Test
    public void testGetExtensionLoaderNoJoinSPI() {
        try {
            ExtensionLoader.getExtensionLoader(NoJoinSPI.class).getJoin("subNoJoinSPI");
            fail();
        } catch (IllegalStateException expected) {
            assertThat(expected.getMessage(), containsString("load extension resources error,class org.dromara.soul.spi.fixture.SubNoJoinSPI with Join annotation"));
        }
    }

    /**
     * test ExtensionLoader.getJoin() param SPI class can not instantiated case.
     */
    @Test
    public void testGetExtensionLoaderCanNotInstantiatedSPI() {
        try {
            ExtensionLoader.getExtensionLoader(JdbcSPI.class).getJoin("canNotInstantiated");
            fail();
        } catch (IllegalStateException expected) {
            assertThat(expected.getMessage(), containsString(
                    "Extension instance(name: canNotInstantiated, class: class org.dromara.soul.spi.fixture.CanNotInstantiatedSPI)  "
                            + "could not be instantiated: Class org.dromara.soul.spi.ExtensionLoader "
                            + "can not access a member of class org.dromara.soul.spi.fixture.CanNotInstantiatedSPI with modifiers \"private\""));
        }
    }

    /**
     * test loadClass duplicate class case.
     */
    @Test
    public void testLoadClassDuplicateKey() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        Method loadClassMethod = getLoadClassMethod();
        ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(JdbcSPI.class);
        Map<String, Class<?>> classes = new HashMap<>();
        loadClassMethod.invoke(extensionLoader, classes, "mysql", "org.dromara.soul.spi.fixture.MysqlSPI");
        try {
            loadClassMethod.invoke(extensionLoader, classes, "mysql", "org.dromara.soul.spi.fixture.OracleSPI");
            fail();
        } catch (InvocationTargetException expect) {
            assertThat(expect.getTargetException().getMessage(), containsString(
                    "load extension resources error,Duplicate class org.dromara.soul.spi.fixture.JdbcSPI name mysql on "
                            + "org.dromara.soul.spi.fixture.MysqlSPI or org.dromara.soul.spi.fixture.OracleSPI"));
        }
    }

    /**
     * test loadResources url IO Exception case.
     */
    @Test
    public void loadResourcesIOException()
            throws NoSuchMethodException, MalformedURLException, IllegalAccessException {
        Method loadResourcesMethod = getLoadResources();
        ExtensionLoader extensionLoader = ExtensionLoader.getExtensionLoader(JdbcSPI.class);
        try {
            loadResourcesMethod.invoke(extensionLoader, new HashMap<>(),
                    new URL("file:/org.dromara.soul.spi.fixture.NoExistSPI"));
            fail();
        } catch (InvocationTargetException expect) {
            assertThat(expect.getTargetException().getMessage(), containsString("load extension resources error"));
        }
    }

    /**
     * get private loadClass method.
     */
    private Method getLoadClassMethod() throws NoSuchMethodException {
        Method method = ExtensionLoader.class.getDeclaredMethod("loadClass", Map.class, String.class, String.class);
        method.setAccessible(true);
        return method;
    }

    /**
     * get private loadResources method.
     */
    private Method getLoadResources() throws NoSuchMethodException {
        Method method = ExtensionLoader.class.getDeclaredMethod("loadResources", Map.class, URL.class);
        method.setAccessible(true);
        return method;
    }
}

字节码生成类

// ApplicationConfigCache
Class<?> prxClazz = classDefinition.annotateType(AnnotationDescription.Builder.ofType(Servant.class).build())
                                    .make()
                                    .load(Servant.class.getClassLoader(), ClassLoadingStrategy.Default.INJECTION)
                                    .getLoaded();
assert communicator != null;
prxClassCache.put(metaData.getServiceName(), prxClazz);


@RunWith(MockitoJUnitRunner.class)
public final class ApplicationConfigCacheTest {

    private ApplicationConfigCache applicationConfigCacheUnderTest;

    @Before
    public void setUp() {
        applicationConfigCacheUnderTest = ApplicationConfigCache.getInstance();
    }

    @Test
    public void testGet() throws ClassNotFoundException {
        final String rpcExt = "{\"methodInfo\":[{\"methodName\":\"method1\",\"params\":"
                + "[{\"left\":\"int\",\"right\":\"param1\"},{\"left\":\"java.lang.Integer\","
                + "\"right\":\"param2\"}],\"returnType\":\"java.lang.String\"}]}";
        final MetaData metaData = new MetaData("id", "127.0.0.1:8080", "contextPath",
                "path5", RpcTypeEnum.TARS.getName(), "serviceName5", "method1",
                "parameterTypes", rpcExt, false);
        applicationConfigCacheUnderTest.initPrx(metaData);
        final TarsInvokePrxList result = applicationConfigCacheUnderTest.get("path5");
        assertNotNull(result);
        assertEquals("promise_method1", result.getMethod().getName());
        assertEquals(2, result.getParamTypes().length);
        assertEquals(2, result.getParamNames().length);
        Class<?> prxClazz = Class.forName(PrxInfoUtil.getPrxName(metaData));
        assertTrue(Arrays.stream(prxClazz.getAnnotations()).anyMatch(annotation -> annotation instanceof Servant));
    }
}

文章作者: HoldDie
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 HoldDie !
评论
 上一篇
Java进阶之JVM实战 Java进阶之JVM实战
1. 使用自定义Classloader机制,实现xlass的加载1.1 类加载流程BootStrap 加载路径System.getProperty("sun.boot.class.path") 输出结果如下: xxx/jre/lib/re
2021-02-24
下一篇 
响应式编程(一) 响应式编程(一)
1. 响应式编程Reactor是反应式编程范例的实现,可以总结如下:反应式编程是一种异步编程范式,涉及数据流和变化的传播。这意味着可以通过所采用的编程语言轻松地表达静态(例如数组)或动态(例如事件发射器)数据流。 作为响应式编程方向的第一步
  目录