You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@dubbo.apache.org by li...@apache.org on 2021/01/30 11:28:22 UTC

[dubbo-spi-extensions] 10/39: move some extension unit tests to here.

This is an automated email from the ASF dual-hosted git repository.

liujun pushed a commit to branch 2.7.x
in repository https://gitbox.apache.org/repos/asf/dubbo-spi-extensions.git

commit a463413bf7ad58d52fe766d99ed4128becd5418a
Author: ken.lj <ke...@gmail.com>
AuthorDate: Thu Sep 3 14:07:55 2020 +0800

    move some extension unit tests to here.
---
 .../com/alibaba/dubbo/remoting/p2p/Networker.java  |  22 +
 .../rpc/protocol/thrift/ClassNameGenerator.java    |  22 +
 dubbo-test/pom.xml                                 |  42 +-
 .../apache/dubbo/config/AbstractConfigTest.java    | 927 +++++++++++++++++++++
 .../dubbo/config/AbstractInterfaceConfigTest.java  | 354 ++++++++
 .../dubbo/config/AbstractMethodConfigTest.java     | 126 +++
 .../dubbo/config/AbstractReferenceConfigTest.java  | 212 +++++
 .../dubbo/config/AbstractServiceConfigTest.java    | 184 ++++
 .../apache/dubbo/config/ApplicationConfigTest.java | 217 +++++
 .../apache/dubbo/config/ArgumentConfigTest.java    |  63 ++
 .../dubbo/config/ConfigCenterConfigTest.java       |  44 +
 .../apache/dubbo/config/ConsumerConfigTest.java    |  81 ++
 .../org/apache/dubbo/config/MethodConfigTest.java  | 240 ++++++
 .../org/apache/dubbo/config/ModuleConfigTest.java  | 104 +++
 .../org/apache/dubbo/config/MonitorConfigTest.java | 107 +++
 .../apache/dubbo/config/ProtocolConfigTest.java    | 204 +++++
 .../apache/dubbo/config/ProviderConfigTest.java    | 219 +++++
 .../apache/dubbo/config/ReferenceConfigTest.java   | 159 ++++
 .../apache/dubbo/config/RegistryConfigTest.java    | 190 +++++
 .../org/apache/dubbo/config/ServiceConfigTest.java | 264 ++++++
 .../test/java/org/apache/dubbo/config/api/Box.java |  23 +
 .../org/apache/dubbo/config/api/DemoException.java |  42 +
 .../org/apache/dubbo/config/api/DemoService.java   |  37 +
 .../java/org/apache/dubbo/config/api/Greeting.java |  24 +
 .../java/org/apache/dubbo/config/api/User.java     |  65 ++
 .../ConsulDubboServiceConsumerBootstrap.java       |  52 ++
 .../ConsulDubboServiceProviderBootstrap.java       |  42 +
 .../dubbo/config/bootstrap/DubboBootstrapTest.java | 154 ++++
 .../bootstrap/DubboServiceConsumerBootstrap.java   |  58 ++
 .../bootstrap/DubboServiceProviderBootstrap.java   |  95 +++
 .../DubboServiceProviderMinimumBootstrap.java      |  38 +
 .../apache/dubbo/config/bootstrap/EchoService.java |  31 +
 .../dubbo/config/bootstrap/EchoServiceImpl.java    |  36 +
 .../EtcdDubboServiceConsumerBootstrap.java         |  51 ++
 .../EtcdDubboServiceProviderBootstrap.java         |  94 +++
 .../NacosDubboServiceConsumerBootstrap.java        |  56 ++
 .../NacosDubboServiceProviderBootstrap.java        |  51 ++
 .../ZookeeperDubboServiceConsumerBootstrap.java    |  55 ++
 .../ZookeeperDubboServiceProviderBootstrap.java    |  43 +
 .../bootstrap/builders/AbstractBuilderTest.java    | 126 +++
 .../builders/AbstractInterfaceBuilderTest.java     | 311 +++++++
 .../builders/AbstractMethodBuilderTest.java        | 196 +++++
 .../builders/AbstractReferenceBuilderTest.java     | 151 ++++
 .../builders/AbstractServiceBuilderTest.java       | 245 ++++++
 .../bootstrap/builders/ApplicationBuilderTest.java | 255 ++++++
 .../bootstrap/builders/ArgumentBuilderTest.java    |  63 ++
 .../builders/ConfigCenterBuilderTest.java          | 169 ++++
 .../bootstrap/builders/ConsumerBuilderTest.java    |  95 +++
 .../builders/MetadataReportBuilderTest.java        | 151 ++++
 .../bootstrap/builders/MethodBuilderTest.java      | 189 +++++
 .../bootstrap/builders/ModuleBuilderTest.java      | 112 +++
 .../bootstrap/builders/MonitorBuilderTest.java     | 135 +++
 .../bootstrap/builders/ProtocolBuilderTest.java    | 338 ++++++++
 .../bootstrap/builders/ProviderBuilderTest.java    | 227 +++++
 .../bootstrap/builders/ReferenceBuilderTest.java   | 125 +++
 .../bootstrap/builders/RegistryBuilderTest.java    | 256 ++++++
 .../bootstrap/builders/ServiceBuilderTest.java     | 131 +++
 .../DubboInterfaceConsumerBootstrap.java           |  57 ++
 .../apache/dubbo/config/bootstrap/rest/User.java   |  77 ++
 .../dubbo/config/bootstrap/rest/UserService.java   |  45 +
 .../config/bootstrap/rest/UserServiceImpl.java     |  32 +
 .../apache/dubbo/config/cache/CacheService.java    |  26 +
 .../dubbo/config/cache/CacheServiceImpl.java       |  32 +
 .../org/apache/dubbo/config/cache/CacheTest.java   | 140 ++++
 .../config/consumer/DemoActionByAnnotation.java    |  35 +
 .../dubbo/config/consumer/DemoActionBySetter.java  |  36 +
 .../dubbo/config/consumer/DemoInterceptor.java     |  31 +
 .../PublishingServiceDefinitionListenerTest.java   |  94 +++
 .../DelegateProviderMetaDataInvokerTest.java       |  60 ++
 .../apache/dubbo/config/mock/GreetingLocal1.java   |  21 +
 .../apache/dubbo/config/mock/GreetingLocal2.java   |  26 +
 .../apache/dubbo/config/mock/GreetingLocal3.java   |  32 +
 .../apache/dubbo/config/mock/GreetingMock1.java    |  20 +
 .../apache/dubbo/config/mock/GreetingMock2.java    |  29 +
 .../org/apache/dubbo/config/mock/MockCluster.java  |  29 +
 .../org/apache/dubbo/config/mock/MockCodec.java    |  37 +
 .../apache/dubbo/config/mock/MockDispatcher.java   |  29 +
 .../apache/dubbo/config/mock/MockExchanger.java    |  37 +
 .../dubbo/config/mock/MockExporterListener.java    |  34 +
 .../org/apache/dubbo/config/mock/MockFilter.java   |  30 +
 .../dubbo/config/mock/MockInvokerListener.java     |  33 +
 .../apache/dubbo/config/mock/MockLoadBalance.java  |  32 +
 .../org/apache/dubbo/config/mock/MockProtocol.java |  89 ++
 .../apache/dubbo/config/mock/MockProtocol2.java    |  48 ++
 .../apache/dubbo/config/mock/MockProxyFactory.java |  39 +
 .../org/apache/dubbo/config/mock/MockRegistry.java | 110 +++
 .../dubbo/config/mock/MockRegistryFactory.java     |  37 +
 .../dubbo/config/mock/MockRegistryFactory2.java    |  31 +
 .../dubbo/config/mock/MockStatusChecker.java       |  28 +
 .../dubbo/config/mock/MockTelnetHandler.java       |  29 +
 .../apache/dubbo/config/mock/MockThreadPool.java   |  30 +
 .../apache/dubbo/config/mock/MockTransporter.java  |  42 +
 .../apache/dubbo/config/mock/TestProxyFactory.java |  33 +
 .../config/provider/impl/DemoServiceImpl.java      |  51 ++
 .../config/url/ExporterSideConfigUrlTest.java      | 102 +++
 .../dubbo/config/url/InvokerSideConfigUrlTest.java | 217 +++++
 .../dubbo/config/url/RpcConfigGetSetProxy.java     | 166 ++++
 .../org/apache/dubbo/config/url/UrlTestBase.java   | 202 +++++
 .../dubbo/config/utils/MockReferenceConfig.java    |  59 ++
 .../config/utils/ReferenceConfigCacheTest.java     | 151 ++++
 .../dubbo/config/utils/XxxMockReferenceConfig.java |  59 ++
 .../dubbo/config/utils/service/FooService.java     |  23 +
 .../dubbo/config/utils/service/FooServiceImpl.java |  23 +
 .../dubbo/config/utils/service/XxxService.java     |  23 +
 .../dubbo/config/utils/service/XxxServiceImpl.java |  23 +
 .../metadata/MetadataServiceExporterTest.java      |  42 +
 .../org.apache.dubbo.common.status.StatusChecker   |  18 +
 .../org.apache.dubbo.common.threadpool.ThreadPool  |  18 +
 .../org.apache.dubbo.registry.RegistryFactory      |   2 +
 .../services/org.apache.dubbo.remoting.Codec       |  18 +
 .../services/org.apache.dubbo.remoting.Dispatcher  |  18 +
 .../services/org.apache.dubbo.remoting.Transporter |  18 +
 .../org.apache.dubbo.remoting.exchange.Exchanger   |  18 +
 .../org.apache.dubbo.remoting.telnet.TelnetHandler |  18 +
 .../services/org.apache.dubbo.rpc.ExporterListener |  18 +
 .../META-INF/services/org.apache.dubbo.rpc.Filter  |   1 +
 .../services/org.apache.dubbo.rpc.InvokerListener  |   1 +
 .../services/org.apache.dubbo.rpc.Protocol         |   2 +
 .../services/org.apache.dubbo.rpc.ProxyFactory     |   2 +
 .../services/org.apache.dubbo.rpc.cluster.Cluster  |   1 +
 .../org.apache.dubbo.rpc.cluster.LoadBalance       |   1 +
 dubbo-test/src/test/resources/dubbo.properties     |   2 +
 dubbo-test/src/test/resources/log4j.xml            |  28 +
 pom.xml                                            |  74 ++
 124 files changed, 11071 insertions(+), 1 deletion(-)

diff --git a/dubbo-spi-remoting/dubbo-remoting-p2p/src/main/java/com/alibaba/dubbo/remoting/p2p/Networker.java b/dubbo-spi-remoting/dubbo-remoting-p2p/src/main/java/com/alibaba/dubbo/remoting/p2p/Networker.java
new file mode 100644
index 0000000..a2f9f41
--- /dev/null
+++ b/dubbo-spi-remoting/dubbo-remoting-p2p/src/main/java/com/alibaba/dubbo/remoting/p2p/Networker.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.dubbo.remoting.p2p;
+
+@Deprecated
+public interface Networker extends org.apache.dubbo.remoting.p2p.Networker {
+}
diff --git a/dubbo-spi-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ClassNameGenerator.java b/dubbo-spi-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ClassNameGenerator.java
new file mode 100644
index 0000000..dec29d3
--- /dev/null
+++ b/dubbo-spi-rpc/dubbo-rpc-thrift/src/main/java/com/alibaba/dubbo/rpc/protocol/thrift/ClassNameGenerator.java
@@ -0,0 +1,22 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.alibaba.dubbo.rpc.protocol.thrift;
+
+@Deprecated
+public interface ClassNameGenerator extends org.apache.dubbo.rpc.protocol.thrift.ClassNameGenerator {
+}
diff --git a/dubbo-test/pom.xml b/dubbo-test/pom.xml
index 66720dc..9b688b6 100644
--- a/dubbo-test/pom.xml
+++ b/dubbo-test/pom.xml
@@ -26,14 +26,48 @@
 
     <artifactId>dubbo-test</artifactId>
 
+    <properties>
+        <skip_maven_deploy>true</skip_maven_deploy>
+    </properties>
+
     <dependencies>
         <dependency>
             <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-config-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-registry-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-metadata-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-monitor-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-remoting-api</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-rpc-injvm</artifactId>
+            <version>${project.parent.version}</version>
+        </dependency>
+
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-rpc-dubbo</artifactId>
             <version>${project.parent.version}</version>
             <scope>test</scope>
         </dependency>
-
         <dependency>
             <groupId>org.apache.dubbo</groupId>
             <artifactId>dubbo-rpc-rest</artifactId>
@@ -190,6 +224,12 @@
             <version>${project.parent.version}</version>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>org.apache.dubbo</groupId>
+            <artifactId>dubbo-filter-cache</artifactId>
+            <version>${project.parent.version}</version>
+            <scope>test</scope>
+        </dependency>
     </dependencies>
 
     <build>
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
new file mode 100644
index 0000000..041cd75
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractConfigTest.java
@@ -0,0 +1,927 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.config.support.Parameter;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.lang.reflect.Field;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Properties;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.junit.jupiter.api.Assertions.fail;
+
+public class AbstractConfigTest {
+
+    //FIXME
+    /*@Test
+    public void testAppendProperties1() throws Exception {
+        try {
+            System.setProperty("dubbo.properties.i", "1");
+            System.setProperty("dubbo.properties.c", "c");
+            System.setProperty("dubbo.properties.b", "2");
+            System.setProperty("dubbo.properties.d", "3");
+            System.setProperty("dubbo.properties.f", "4");
+            System.setProperty("dubbo.properties.l", "5");
+            System.setProperty("dubbo.properties.s", "6");
+            System.setProperty("dubbo.properties.str", "dubbo");
+            System.setProperty("dubbo.properties.bool", "true");
+            PropertiesConfig config = new PropertiesConfig();
+            AbstractConfig.appendProperties(config);
+            Assertions.assertEquals(1, config.getI());
+            Assertions.assertEquals('c', config.getC());
+            Assertions.assertEquals((byte) 0x02, config.getB());
+            Assertions.assertEquals(3d, config.getD());
+            Assertions.assertEquals(4f, config.getF());
+            Assertions.assertEquals(5L, config.getL());
+            Assertions.assertEquals(6, config.getS());
+            Assertions.assertEquals("dubbo", config.getStr());
+            Assertions.assertTrue(config.isBool());
+        } finally {
+            System.clearProperty("dubbo.properties.i");
+            System.clearProperty("dubbo.properties.c");
+            System.clearProperty("dubbo.properties.b");
+            System.clearProperty("dubbo.properties.d");
+            System.clearProperty("dubbo.properties.f");
+            System.clearProperty("dubbo.properties.l");
+            System.clearProperty("dubbo.properties.s");
+            System.clearProperty("dubbo.properties.str");
+            System.clearProperty("dubbo.properties.bool");
+        }
+    }
+
+    @Test
+    public void testAppendProperties2() throws Exception {
+        try {
+            System.setProperty("dubbo.properties.two.i", "2");
+            PropertiesConfig config = new PropertiesConfig("two");
+            AbstractConfig.appendProperties(config);
+            Assertions.assertEquals(2, config.getI());
+        } finally {
+            System.clearProperty("dubbo.properties.two.i");
+        }
+    }
+
+    @Test
+    public void testAppendProperties3() throws Exception {
+        try {
+            Properties p = new Properties();
+            p.put("dubbo.properties.str", "dubbo");
+            ConfigUtils.setProperties(p);
+            PropertiesConfig config = new PropertiesConfig();
+            AbstractConfig.appendProperties(config);
+            Assertions.assertEquals("dubbo", config.getStr());
+        } finally {
+            System.clearProperty(Constants.DUBBO_PROPERTIES_KEY);
+            ConfigUtils.setProperties(null);
+        }
+    }*/
+
+    @Test
+    public void testAppendParameters1() throws Exception {
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("num", "ONE");
+        AbstractConfig.appendParameters(parameters, new ParameterConfig(1, "hello/world", 30, "password"), "prefix");
+        Assertions.assertEquals("one", parameters.get("prefix.key.1"));
+        Assertions.assertEquals("two", parameters.get("prefix.key.2"));
+        Assertions.assertEquals("ONE,1", parameters.get("prefix.num"));
+        Assertions.assertEquals("hello%2Fworld", parameters.get("prefix.naming"));
+        Assertions.assertEquals("30", parameters.get("prefix.age"));
+        Assertions.assertTrue(parameters.containsKey("prefix.key-2"));
+        Assertions.assertTrue(parameters.containsKey("prefix.key.2"));
+        Assertions.assertFalse(parameters.containsKey("prefix.secret"));
+    }
+
+    @Test
+    public void testAppendParameters2() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            Map<String, String> parameters = new HashMap<String, String>();
+            AbstractConfig.appendParameters(parameters, new ParameterConfig());
+        });
+    }
+
+    @Test
+    public void testAppendParameters3() throws Exception {
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractConfig.appendParameters(parameters, null);
+        assertTrue(parameters.isEmpty());
+    }
+
+    @Test
+    public void testAppendParameters4() throws Exception {
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractConfig.appendParameters(parameters, new ParameterConfig(1, "hello/world", 30, "password"));
+        Assertions.assertEquals("one", parameters.get("key.1"));
+        Assertions.assertEquals("two", parameters.get("key.2"));
+        Assertions.assertEquals("1", parameters.get("num"));
+        Assertions.assertEquals("hello%2Fworld", parameters.get("naming"));
+        Assertions.assertEquals("30", parameters.get("age"));
+    }
+
+    @Test
+    public void testAppendAttributes1() throws Exception {
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        AbstractConfig.appendAttributes(parameters, new AttributeConfig('l', true, (byte) 0x01), "prefix");
+        Assertions.assertEquals('l', parameters.get("prefix.let"));
+        Assertions.assertEquals(true, parameters.get("prefix.activate"));
+        Assertions.assertFalse(parameters.containsKey("prefix.flag"));
+    }
+
+    @Test
+    public void testAppendAttributes2() throws Exception {
+        Map<String, Object> parameters = new HashMap<String, Object>();
+        AbstractConfig.appendAttributes(parameters, new AttributeConfig('l', true, (byte) 0x01));
+        Assertions.assertEquals('l', parameters.get("let"));
+        Assertions.assertEquals(true, parameters.get("activate"));
+        Assertions.assertFalse(parameters.containsKey("flag"));
+    }
+
+    @Test
+    public void checkExtension() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> ConfigValidationUtils.checkExtension(Greeting.class, "hello", "world"));
+    }
+
+    @Test
+    public void checkMultiExtension1() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> ConfigValidationUtils.checkMultiExtension(Greeting.class, "hello", "default,world"));
+    }
+
+    @Test
+    public void checkMultiExtension2() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> ConfigValidationUtils.checkMultiExtension(Greeting.class, "hello", "default,-world"));
+    }
+
+    @Test
+    public void checkLength() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i <= 200; i++) {
+                builder.append("a");
+            }
+            ConfigValidationUtils.checkLength("hello", builder.toString());
+        });
+    }
+
+    @Test
+    public void checkPathLength() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            StringBuilder builder = new StringBuilder();
+            for (int i = 0; i <= 200; i++) {
+                builder.append("a");
+            }
+            ConfigValidationUtils.checkPathLength("hello", builder.toString());
+        });
+    }
+
+    @Test
+    public void checkName() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> ConfigValidationUtils.checkName("hello", "world%"));
+    }
+
+    @Test
+    public void checkNameHasSymbol() throws Exception {
+        try {
+            ConfigValidationUtils.checkNameHasSymbol("hello", ":*,/ -0123\tabcdABCD");
+            ConfigValidationUtils.checkNameHasSymbol("mock", "force:return world");
+        } catch (Exception e) {
+            fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkKey() throws Exception {
+        try {
+            ConfigValidationUtils.checkKey("hello", "*,-0123abcdABCD");
+        } catch (Exception e) {
+            fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkMultiName() throws Exception {
+        try {
+            ConfigValidationUtils.checkMultiName("hello", ",-._0123abcdABCD");
+        } catch (Exception e) {
+            fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkPathName() throws Exception {
+        try {
+            ConfigValidationUtils.checkPathName("hello", "/-$._0123abcdABCD");
+        } catch (Exception e) {
+            fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkMethodName() throws Exception {
+        try {
+            ConfigValidationUtils.checkMethodName("hello", "abcdABCD0123abcd");
+        } catch (Exception e) {
+            fail("the value should be legal.");
+        }
+
+        try {
+            ConfigValidationUtils.checkMethodName("hello", "0a");
+            fail("the value should be illegal.");
+        } catch (Exception e) {
+            // ignore
+        }
+    }
+
+    @Test
+    public void checkParameterName() throws Exception {
+        Map<String, String> parameters = Collections.singletonMap("hello", ":*,/-._0123abcdABCD");
+        try {
+            ConfigValidationUtils.checkParameterName(parameters);
+        } catch (Exception e) {
+            fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    @Config(interfaceClass = Greeting.class, filter = {"f1, f2"}, listener = {"l1, l2"},
+            parameters = {"k1", "v1", "k2", "v2"})
+    public void appendAnnotation() throws Exception {
+        Config config = getClass().getMethod("appendAnnotation").getAnnotation(Config.class);
+        AnnotationConfig annotationConfig = new AnnotationConfig();
+        annotationConfig.appendAnnotation(Config.class, config);
+        Assertions.assertSame(Greeting.class, annotationConfig.getInterface());
+        Assertions.assertEquals("f1, f2", annotationConfig.getFilter());
+        Assertions.assertEquals("l1, l2", annotationConfig.getListener());
+        Assertions.assertEquals(2, annotationConfig.getParameters().size());
+        Assertions.assertEquals("v1", annotationConfig.getParameters().get("k1"));
+        Assertions.assertEquals("v2", annotationConfig.getParameters().get("k2"));
+        assertThat(annotationConfig.toString(), Matchers.containsString("filter=\"f1, f2\" "));
+        assertThat(annotationConfig.toString(), Matchers.containsString("listener=\"l1, l2\" "));
+    }
+
+    @Test
+    public void testRefreshAll() {
+        try {
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setAddress("override-config://127.0.0.1:2181");
+            overrideConfig.setProtocol("override-config");
+            overrideConfig.setEscape("override-config://");
+            overrideConfig.setExclude("override-config");
+
+            Map<String, String> external = new HashMap<>();
+            external.put("dubbo.override.address", "external://127.0.0.1:2181");
+            // @Parameter(exclude=true)
+            external.put("dubbo.override.exclude", "external");
+            // @Parameter(key="key1", useKeyAsProperty=false)
+            external.put("dubbo.override.key", "external");
+            // @Parameter(key="key2", useKeyAsProperty=true)
+            external.put("dubbo.override.key2", "external");
+            ApplicationModel.getEnvironment().setExternalConfigMap(external);
+            ApplicationModel.getEnvironment().initialize();
+
+            System.setProperty("dubbo.override.address", "system://127.0.0.1:2181");
+            System.setProperty("dubbo.override.protocol", "system");
+            // this will not override, use 'key' instead, @Parameter(key="key1", useKeyAsProperty=false)
+            System.setProperty("dubbo.override.key1", "system");
+            System.setProperty("dubbo.override.key2", "system");
+
+            // Load configuration from  system properties -> externalConfiguration -> RegistryConfig -> dubbo.properties
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("system://127.0.0.1:2181", overrideConfig.getAddress());
+            Assertions.assertEquals("system", overrideConfig.getProtocol());
+            Assertions.assertEquals("override-config://", overrideConfig.getEscape());
+            Assertions.assertEquals("external", overrideConfig.getKey());
+            Assertions.assertEquals("system", overrideConfig.getUseKeyAsProperty());
+        } finally {
+            System.clearProperty("dubbo.override.address");
+            System.clearProperty("dubbo.override.protocol");
+            System.clearProperty("dubbo.override.key1");
+            System.clearProperty("dubbo.override.key2");
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+        }
+    }
+
+    @Test
+    public void testRefreshSystem() {
+        try {
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setAddress("override-config://127.0.0.1:2181");
+            overrideConfig.setProtocol("override-config");
+            overrideConfig.setEscape("override-config://");
+            overrideConfig.setExclude("override-config");
+
+            System.setProperty("dubbo.override.address", "system://127.0.0.1:2181");
+            System.setProperty("dubbo.override.protocol", "system");
+            System.setProperty("dubbo.override.key", "system");
+
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("system://127.0.0.1:2181", overrideConfig.getAddress());
+            Assertions.assertEquals("system", overrideConfig.getProtocol());
+            Assertions.assertEquals("override-config://", overrideConfig.getEscape());
+            Assertions.assertEquals("system", overrideConfig.getKey());
+        } finally {
+            System.clearProperty("dubbo.override.address");
+            System.clearProperty("dubbo.override.protocol");
+            System.clearProperty("dubbo.override.key1");
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+        }
+    }
+
+    @Test
+    public void testRefreshProperties() throws Exception {
+        try {
+            ApplicationModel.getEnvironment().setExternalConfigMap(new HashMap<>());
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setAddress("override-config://127.0.0.1:2181");
+            overrideConfig.setProtocol("override-config");
+            overrideConfig.setEscape("override-config://");
+
+            Properties properties = new Properties();
+            properties.load(this.getClass().getResourceAsStream("/dubbo.properties"));
+            ConfigUtils.setProperties(properties);
+
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("override-config://127.0.0.1:2181", overrideConfig.getAddress());
+            Assertions.assertEquals("override-config", overrideConfig.getProtocol());
+            Assertions.assertEquals("override-config://", overrideConfig.getEscape());
+            //Assertions.assertEquals("properties", overrideConfig.getUseKeyAsProperty());
+        } finally {
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+            ConfigUtils.setProperties(null);
+        }
+    }
+
+    @Test
+    public void testRefreshExternal() {
+        try {
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setAddress("override-config://127.0.0.1:2181");
+            overrideConfig.setProtocol("override-config");
+            overrideConfig.setEscape("override-config://");
+            overrideConfig.setExclude("override-config");
+
+            Map<String, String> external = new HashMap<>();
+            external.put("dubbo.override.address", "external://127.0.0.1:2181");
+            external.put("dubbo.override.protocol", "external");
+            external.put("dubbo.override.escape", "external://");
+            // @Parameter(exclude=true)
+            external.put("dubbo.override.exclude", "external");
+            // @Parameter(key="key1", useKeyAsProperty=false)
+            external.put("dubbo.override.key", "external");
+            // @Parameter(key="key2", useKeyAsProperty=true)
+            external.put("dubbo.override.key2", "external");
+            ApplicationModel.getEnvironment().setExternalConfigMap(external);
+            ApplicationModel.getEnvironment().initialize();
+
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("external://127.0.0.1:2181", overrideConfig.getAddress());
+            Assertions.assertEquals("external", overrideConfig.getProtocol());
+            Assertions.assertEquals("external://", overrideConfig.getEscape());
+            Assertions.assertEquals("external", overrideConfig.getExclude());
+            Assertions.assertEquals("external", overrideConfig.getKey());
+            Assertions.assertEquals("external", overrideConfig.getUseKeyAsProperty());
+        } finally {
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+        }
+    }
+
+    @Test
+    public void testRefreshById() {
+        try {
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setId("override-id");
+            overrideConfig.setAddress("override-config://127.0.0.1:2181");
+            overrideConfig.setProtocol("override-config");
+            overrideConfig.setEscape("override-config://");
+            overrideConfig.setExclude("override-config");
+
+            Map<String, String> external = new HashMap<>();
+            external.put("dubbo.override.override-id.address", "external-override-id://127.0.0.1:2181");
+            external.put("dubbo.override.address", "external://127.0.0.1:2181");
+            // @Parameter(exclude=true)
+            external.put("dubbo.override.exclude", "external");
+            // @Parameter(key="key1", useKeyAsProperty=false)
+            external.put("dubbo.override.key", "external");
+            // @Parameter(key="key2", useKeyAsProperty=true)
+            external.put("dubbo.override.key2", "external");
+            ApplicationModel.getEnvironment().setExternalConfigMap(external);
+            ApplicationModel.getEnvironment().initialize();
+
+            ConfigCenterConfig configCenter = new ConfigCenterConfig();
+            overrideConfig.setConfigCenter(configCenter);
+            // Load configuration from  system properties -> externalConfiguration -> RegistryConfig -> dubbo.properties
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("external-override-id://127.0.0.1:2181", overrideConfig.getAddress());
+            Assertions.assertEquals("override-config", overrideConfig.getProtocol());
+            Assertions.assertEquals("override-config://", overrideConfig.getEscape());
+            Assertions.assertEquals("external", overrideConfig.getKey());
+            Assertions.assertEquals("external", overrideConfig.getUseKeyAsProperty());
+        } finally {
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+        }
+    }
+
+    @Test
+    public void testRefreshParameters() {
+        try {
+            Map<String, String> parameters = new HashMap<>();
+            parameters.put("key1", "value1");
+            parameters.put("key2", "value2");
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setParameters(parameters);
+
+
+            Map<String, String> external = new HashMap<>();
+            external.put("dubbo.override.parameters", "[{key3:value3},{key4:value4},{key2:value5}]");
+            ApplicationModel.getEnvironment().setExternalConfigMap(external);
+            ApplicationModel.getEnvironment().initialize();
+
+            ConfigCenterConfig configCenter = new ConfigCenterConfig();
+            overrideConfig.setConfigCenter(configCenter);
+            // Load configuration from  system properties -> externalConfiguration -> RegistryConfig -> dubbo.properties
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("value1", overrideConfig.getParameters().get("key1"));
+            Assertions.assertEquals("value5", overrideConfig.getParameters().get("key2"));
+            Assertions.assertEquals("value3", overrideConfig.getParameters().get("key3"));
+            Assertions.assertEquals("value4", overrideConfig.getParameters().get("key4"));
+
+            System.setProperty("dubbo.override.parameters", "[{key3:value6}]");
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("value6", overrideConfig.getParameters().get("key3"));
+            Assertions.assertEquals("value4", overrideConfig.getParameters().get("key4"));
+        } finally {
+            System.clearProperty("dubbo.override.parameters");
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+        }
+    }
+
+    @Test
+    public void testOnlyPrefixedKeyTakeEffect() {
+        try {
+            OverrideConfig overrideConfig = new OverrideConfig();
+            overrideConfig.setNotConflictKey("value-from-config");
+
+            Map<String, String> external = new HashMap<>();
+            external.put("notConflictKey", "value-from-external");
+
+            try {
+                Map<String, String> map = new HashMap<>();
+                map.put("notConflictKey", "value-from-env");
+                map.put("dubbo.override.notConflictKey2", "value-from-env");
+                setOsEnv(map);
+            } catch (Exception e) {
+                // ignore
+                e.printStackTrace();
+            }
+
+            ApplicationModel.getEnvironment().setExternalConfigMap(external);
+
+            overrideConfig.refresh();
+
+            Assertions.assertEquals("value-from-config", overrideConfig.getNotConflictKey());
+            Assertions.assertEquals("value-from-env", overrideConfig.getNotConflictKey2());
+        } finally {
+            ApplicationModel.getEnvironment().clearExternalConfigs();
+
+        }
+    }
+
+    @Test
+    public void tetMetaData() {
+        OverrideConfig overrideConfig = new OverrideConfig();
+        overrideConfig.setId("override-id");
+        overrideConfig.setAddress("override-config://127.0.0.1:2181");
+        overrideConfig.setProtocol("override-config");
+        overrideConfig.setEscape("override-config://");
+        overrideConfig.setExclude("override-config");
+
+        Map<String, String> metaData = overrideConfig.getMetaData();
+        Assertions.assertEquals("override-config://127.0.0.1:2181", metaData.get("address"));
+        Assertions.assertEquals("override-config", metaData.get("protocol"));
+        Assertions.assertEquals("override-config://", metaData.get("escape"));
+        Assertions.assertEquals("override-config", metaData.get("exclude"));
+        Assertions.assertNull(metaData.get("key"));
+        Assertions.assertNull(metaData.get("key2"));
+    }
+
+    @Test
+    public void testEquals() {
+        ApplicationConfig application1 = new ApplicationConfig();
+        ApplicationConfig application2 = new ApplicationConfig();
+        application1.setName("app1");
+        application2.setName("app2");
+        Assertions.assertNotEquals(application1, application2);
+        application1.setName("sameName");
+        application2.setName("sameName");
+        Assertions.assertEquals(application1, application2);
+
+        ProtocolConfig protocol1 = new ProtocolConfig();
+        protocol1.setHost("127.0.0.1");// excluded
+        protocol1.setName("dubbo");
+        ProtocolConfig protocol2 = new ProtocolConfig();
+        protocol2.setHost("127.0.0.2");// excluded
+        protocol2.setName("dubbo");
+        Assertions.assertEquals(protocol1, protocol2);
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.ANNOTATION_TYPE})
+    public @interface ConfigField {
+        String value() default "";
+    }
+
+    @Retention(RetentionPolicy.RUNTIME)
+    @Target({ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
+    public @interface Config {
+        Class<?> interfaceClass() default void.class;
+
+        String interfaceName() default "";
+
+        String[] filter() default {};
+
+        String[] listener() default {};
+
+        String[] parameters() default {};
+
+        ConfigField[] configFields() default {};
+
+        ConfigField configField() default @ConfigField;
+    }
+
+    private static class OverrideConfig extends AbstractInterfaceConfig {
+        public String address;
+        public String protocol;
+        public String exclude;
+        public String key;
+        public String useKeyAsProperty;
+        public String escape;
+        public String notConflictKey;
+        public String notConflictKey2;
+
+        public String getAddress() {
+            return address;
+        }
+
+        public void setAddress(String address) {
+            this.address = address;
+        }
+
+        public String getProtocol() {
+            return protocol;
+        }
+
+        public void setProtocol(String protocol) {
+            this.protocol = protocol;
+        }
+
+        @Parameter(excluded = true)
+        public String getExclude() {
+            return exclude;
+        }
+
+        public void setExclude(String exclude) {
+            this.exclude = exclude;
+        }
+
+        @Parameter(key = "key1", useKeyAsProperty = false)
+        public String getKey() {
+            return key;
+        }
+
+        public void setKey(String key) {
+            this.key = key;
+        }
+
+        @Parameter(key = "key2", useKeyAsProperty = true)
+        public String getUseKeyAsProperty() {
+            return useKeyAsProperty;
+        }
+
+        public void setUseKeyAsProperty(String useKeyAsProperty) {
+            this.useKeyAsProperty = useKeyAsProperty;
+        }
+
+        @Parameter(escaped = true)
+        public String getEscape() {
+            return escape;
+        }
+
+        public void setEscape(String escape) {
+            this.escape = escape;
+        }
+
+        public String getNotConflictKey() {
+            return notConflictKey;
+        }
+
+        public void setNotConflictKey(String notConflictKey) {
+            this.notConflictKey = notConflictKey;
+        }
+
+        public String getNotConflictKey2() {
+            return notConflictKey2;
+        }
+
+        public void setNotConflictKey2(String notConflictKey2) {
+            this.notConflictKey2 = notConflictKey2;
+        }
+    }
+
+    private static class PropertiesConfig extends AbstractConfig {
+        private char c;
+        private boolean bool;
+        private byte b;
+        private int i;
+        private long l;
+        private float f;
+        private double d;
+        private short s;
+        private String str;
+
+        PropertiesConfig() {
+        }
+
+        PropertiesConfig(String id) {
+            this.id = id;
+        }
+
+        public char getC() {
+            return c;
+        }
+
+        public void setC(char c) {
+            this.c = c;
+        }
+
+        public boolean isBool() {
+            return bool;
+        }
+
+        public void setBool(boolean bool) {
+            this.bool = bool;
+        }
+
+        public byte getB() {
+            return b;
+        }
+
+        public void setB(byte b) {
+            this.b = b;
+        }
+
+        public int getI() {
+            return i;
+        }
+
+        public void setI(int i) {
+            this.i = i;
+        }
+
+        public long getL() {
+            return l;
+        }
+
+        public void setL(long l) {
+            this.l = l;
+        }
+
+        public float getF() {
+            return f;
+        }
+
+        public void setF(float f) {
+            this.f = f;
+        }
+
+        public double getD() {
+            return d;
+        }
+
+        public void setD(double d) {
+            this.d = d;
+        }
+
+        public String getStr() {
+            return str;
+        }
+
+        public void setStr(String str) {
+            this.str = str;
+        }
+
+        public short getS() {
+            return s;
+        }
+
+        public void setS(short s) {
+            this.s = s;
+        }
+    }
+
+    private static class ParameterConfig {
+        private int number;
+        private String name;
+        private int age;
+        private String secret;
+
+        ParameterConfig() {
+        }
+
+        ParameterConfig(int number, String name, int age, String secret) {
+            this.number = number;
+            this.name = name;
+            this.age = age;
+            this.secret = secret;
+        }
+
+        @Parameter(key = "num", append = true)
+        public int getNumber() {
+            return number;
+        }
+
+        public void setNumber(int number) {
+            this.number = number;
+        }
+
+        @Parameter(key = "naming", append = true, escaped = true, required = true)
+        public String getName() {
+            return name;
+        }
+
+        public void setName(String name) {
+            this.name = name;
+        }
+
+        public int getAge() {
+            return age;
+        }
+
+        public void setAge(int age) {
+            this.age = age;
+        }
+
+        @Parameter(excluded = true)
+        public String getSecret() {
+            return secret;
+        }
+
+        public void setSecret(String secret) {
+            this.secret = secret;
+        }
+
+        public Map getParameters() {
+            Map<String, String> map = new HashMap<String, String>();
+            map.put("key.1", "one");
+            map.put("key-2", "two");
+            return map;
+        }
+    }
+
+    private static class AttributeConfig {
+        private char letter;
+        private boolean activate;
+        private byte flag;
+
+        public AttributeConfig(char letter, boolean activate, byte flag) {
+            this.letter = letter;
+            this.activate = activate;
+            this.flag = flag;
+        }
+
+        @Parameter(attribute = true, key = "let")
+        public char getLetter() {
+            return letter;
+        }
+
+        public void setLetter(char letter) {
+            this.letter = letter;
+        }
+
+        @Parameter(attribute = true)
+        public boolean isActivate() {
+            return activate;
+        }
+
+        public void setActivate(boolean activate) {
+            this.activate = activate;
+        }
+
+        public byte getFlag() {
+            return flag;
+        }
+
+        public void setFlag(byte flag) {
+            this.flag = flag;
+        }
+    }
+
+    private static class AnnotationConfig extends AbstractConfig {
+        private Class interfaceClass;
+        private String filter;
+        private String listener;
+        private Map<String, String> parameters;
+        private String[] configFields;
+
+        public Class getInterface() {
+            return interfaceClass;
+        }
+
+        public void setInterface(Class interfaceName) {
+            this.interfaceClass = interfaceName;
+        }
+
+        public String getFilter() {
+            return filter;
+        }
+
+        public void setFilter(String filter) {
+            this.filter = filter;
+        }
+
+        public String getListener() {
+            return listener;
+        }
+
+        public void setListener(String listener) {
+            this.listener = listener;
+        }
+
+        public Map<String, String> getParameters() {
+            return parameters;
+        }
+
+        public void setParameters(Map<String, String> parameters) {
+            this.parameters = parameters;
+        }
+
+        public String[] getConfigFields() {
+            return configFields;
+        }
+
+        public void setConfigFields(String[] configFields) {
+            this.configFields = configFields;
+        }
+    }
+
+    protected static void setOsEnv(Map<String, String> newenv) throws Exception {
+        try {
+            Class<?> processEnvironmentClass = Class.forName("java.lang.ProcessEnvironment");
+            Field theEnvironmentField = processEnvironmentClass.getDeclaredField("theEnvironment");
+            theEnvironmentField.setAccessible(true);
+            Map<String, String> env = (Map<String, String>) theEnvironmentField.get(null);
+            env.putAll(newenv);
+            Field theCaseInsensitiveEnvironmentField = processEnvironmentClass.getDeclaredField("theCaseInsensitiveEnvironment");
+            theCaseInsensitiveEnvironmentField.setAccessible(true);
+            Map<String, String> cienv = (Map<String, String>) theCaseInsensitiveEnvironmentField.get(null);
+            cienv.putAll(newenv);
+        } catch (NoSuchFieldException e) {
+            Class[] classes = Collections.class.getDeclaredClasses();
+            Map<String, String> env = System.getenv();
+            for (Class cl : classes) {
+                if ("java.util.Collections$UnmodifiableMap".equals(cl.getName())) {
+                    Field field = cl.getDeclaredField("m");
+                    field.setAccessible(true);
+                    Object obj = field.get(env);
+                    Map<String, String> map = (Map<String, String>) obj;
+                    map.clear();
+                    map.putAll(newenv);
+                }
+            }
+        }
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java
new file mode 100644
index 0000000..2bcd960
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java
@@ -0,0 +1,354 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.config.mock.GreetingLocal1;
+import org.apache.dubbo.config.mock.GreetingLocal2;
+import org.apache.dubbo.config.mock.GreetingLocal3;
+import org.apache.dubbo.config.mock.GreetingMock1;
+import org.apache.dubbo.config.mock.GreetingMock2;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+
+import org.junit.jupiter.api.AfterAll;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.File;
+import java.nio.file.Path;
+import java.util.Collections;
+
+public class AbstractInterfaceConfigTest {
+    private static File dubboProperties;
+
+    @BeforeAll
+    public static void setUp(@TempDir Path folder) {
+        dubboProperties = folder.resolve(CommonConstants.DUBBO_PROPERTIES_KEY).toFile();
+        System.setProperty(CommonConstants.DUBBO_PROPERTIES_KEY, dubboProperties.getAbsolutePath());
+    }
+
+    @AfterAll
+    public static void tearDown() {
+        System.clearProperty(CommonConstants.DUBBO_PROPERTIES_KEY);
+    }
+
+    @AfterEach
+    public void tearMethodAfterEachUT() {
+//        ApplicationModel.getConfigManager().clear();
+    }
+
+    @Test
+    public void testCheckRegistry1() {
+        System.setProperty("dubbo.registry.address", "addr1");
+        try {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setApplication(new ApplicationConfig("testCheckRegistry1"));
+            interfaceConfig.checkRegistry();
+            Assertions.assertEquals(1, interfaceConfig.getRegistries().size());
+            Assertions.assertEquals("addr1", interfaceConfig.getRegistries().get(0).getAddress());
+        } finally {
+            System.clearProperty("dubbo.registry.address");
+        }
+    }
+
+    @Test
+    public void testCheckRegistry2() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkRegistry();
+        });
+    }
+
+    @Test
+    public void checkInterfaceAndMethods1() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkInterfaceAndMethods(null, null);
+        });
+    }
+
+    @Test
+    public void checkInterfaceAndMethods2() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkInterfaceAndMethods(AbstractInterfaceConfigTest.class, null);
+        });
+    }
+
+    @Test
+    public void checkInterfaceAndMethod3() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            MethodConfig methodConfig = new MethodConfig();
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkInterfaceAndMethods(Greeting.class, Collections.singletonList(methodConfig));
+        });
+    }
+
+    @Test
+    public void checkInterfaceAndMethod4() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            MethodConfig methodConfig = new MethodConfig();
+            methodConfig.setName("nihao");
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkInterfaceAndMethods(Greeting.class, Collections.singletonList(methodConfig));
+        });
+    }
+
+    @Test
+    public void checkInterfaceAndMethod5() {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setName("hello");
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkInterfaceAndMethods(Greeting.class, Collections.singletonList(methodConfig));
+    }
+
+    @Test
+    public void checkStubAndMock1() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setLocal(GreetingLocal1.class.getName());
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void checkStubAndMock2() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setLocal(GreetingLocal2.class.getName());
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void checkStubAndMock3() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLocal(GreetingLocal3.class.getName());
+        interfaceConfig.checkStubAndLocal(Greeting.class);
+        ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+    }
+
+    @Test
+    public void checkStubAndMock4() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setStub(GreetingLocal1.class.getName());
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void checkStubAndMock5() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setStub(GreetingLocal2.class.getName());
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void checkStubAndMock6() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setStub(GreetingLocal3.class.getName());
+        interfaceConfig.checkStubAndLocal(Greeting.class);
+        ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+    }
+
+    @Test
+    public void checkStubAndMock7() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setMock("return {a, b}");
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void checkStubAndMock8() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setMock(GreetingMock1.class.getName());
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void checkStubAndMock9() {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.setMock(GreetingMock2.class.getName());
+            interfaceConfig.checkStubAndLocal(Greeting.class);
+            ConfigValidationUtils.checkMock(Greeting.class, interfaceConfig);
+        });
+    }
+
+    @Test
+    public void testLocal() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLocal((Boolean) null);
+        Assertions.assertNull(interfaceConfig.getLocal());
+        interfaceConfig.setLocal(true);
+        Assertions.assertEquals("true", interfaceConfig.getLocal());
+        interfaceConfig.setLocal("GreetingMock");
+        Assertions.assertEquals("GreetingMock", interfaceConfig.getLocal());
+    }
+
+    @Test
+    public void testStub() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setStub((Boolean) null);
+        Assertions.assertNull(interfaceConfig.getStub());
+        interfaceConfig.setStub(true);
+        Assertions.assertEquals("true", interfaceConfig.getStub());
+        interfaceConfig.setStub("GreetingMock");
+        Assertions.assertEquals("GreetingMock", interfaceConfig.getStub());
+    }
+
+    @Test
+    public void testCluster() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setCluster("mockcluster");
+        Assertions.assertEquals("mockcluster", interfaceConfig.getCluster());
+    }
+
+    @Test
+    public void testProxy() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setProxy("mockproxyfactory");
+        Assertions.assertEquals("mockproxyfactory", interfaceConfig.getProxy());
+    }
+
+    @Test
+    public void testConnections() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setConnections(1);
+        Assertions.assertEquals(1, interfaceConfig.getConnections().intValue());
+    }
+
+    @Test
+    public void testFilter() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setFilter("mockfilter");
+        Assertions.assertEquals("mockfilter", interfaceConfig.getFilter());
+    }
+
+    @Test
+    public void testListener() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setListener("mockinvokerlistener");
+        Assertions.assertEquals("mockinvokerlistener", interfaceConfig.getListener());
+    }
+
+    @Test
+    public void testLayer() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLayer("layer");
+        Assertions.assertEquals("layer", interfaceConfig.getLayer());
+    }
+
+    @Test
+    public void testApplication() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        interfaceConfig.setApplication(applicationConfig);
+        Assertions.assertSame(applicationConfig, interfaceConfig.getApplication());
+    }
+
+    @Test
+    public void testModule() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        ModuleConfig moduleConfig = new ModuleConfig();
+        interfaceConfig.setModule(moduleConfig);
+        Assertions.assertSame(moduleConfig, interfaceConfig.getModule());
+    }
+
+    @Test
+    public void testRegistry() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        RegistryConfig registryConfig = new RegistryConfig();
+        interfaceConfig.setRegistry(registryConfig);
+        Assertions.assertSame(registryConfig, interfaceConfig.getRegistry());
+    }
+
+    @Test
+    public void testRegistries() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        RegistryConfig registryConfig = new RegistryConfig();
+        interfaceConfig.setRegistries(Collections.singletonList(registryConfig));
+        Assertions.assertEquals(1, interfaceConfig.getRegistries().size());
+        Assertions.assertSame(registryConfig, interfaceConfig.getRegistries().get(0));
+    }
+
+    @Test
+    public void testMonitor() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setMonitor("monitor-addr");
+        Assertions.assertEquals("monitor-addr", interfaceConfig.getMonitor().getAddress());
+        MonitorConfig monitorConfig = new MonitorConfig();
+        interfaceConfig.setMonitor(monitorConfig);
+        Assertions.assertSame(monitorConfig, interfaceConfig.getMonitor());
+    }
+
+    @Test
+    public void testOwner() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setOwner("owner");
+        Assertions.assertEquals("owner", interfaceConfig.getOwner());
+    }
+
+    @Test
+    public void testCallbacks() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setCallbacks(2);
+        Assertions.assertEquals(2, interfaceConfig.getCallbacks().intValue());
+    }
+
+    @Test
+    public void testOnconnect() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setOnconnect("onConnect");
+        Assertions.assertEquals("onConnect", interfaceConfig.getOnconnect());
+    }
+
+    @Test
+    public void testOndisconnect() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setOndisconnect("onDisconnect");
+        Assertions.assertEquals("onDisconnect", interfaceConfig.getOndisconnect());
+    }
+
+    @Test
+    public void testScope() {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setScope("scope");
+        Assertions.assertEquals("scope", interfaceConfig.getScope());
+    }
+
+    public static class InterfaceConfig extends AbstractInterfaceConfig {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java
new file mode 100644
index 0000000..5b82bc8
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isEmptyOrNullString;
+import static org.hamcrest.Matchers.sameInstance;
+
+public class AbstractMethodConfigTest {
+    @Test
+    public void testTimeout() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setTimeout(10);
+        assertThat(methodConfig.getTimeout(), equalTo(10));
+    }
+
+    @Test
+    public void testForks() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setForks(10);
+        assertThat(methodConfig.getForks(), equalTo(10));
+    }
+
+    @Test
+    public void testRetries() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setRetries(3);
+        assertThat(methodConfig.getRetries(), equalTo(3));
+    }
+
+    @Test
+    public void testLoadbalance() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setLoadbalance("mockloadbalance");
+        assertThat(methodConfig.getLoadbalance(), equalTo("mockloadbalance"));
+    }
+
+    @Test
+    public void testAsync() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setAsync(true);
+        assertThat(methodConfig.isAsync(), is(true));
+    }
+
+    @Test
+    public void testActives() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setActives(10);
+        assertThat(methodConfig.getActives(), equalTo(10));
+    }
+
+    @Test
+    public void testSent() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setSent(true);
+        assertThat(methodConfig.getSent(), is(true));
+    }
+
+    @Test
+    public void testMock() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setMock((Boolean) null);
+        assertThat(methodConfig.getMock(), isEmptyOrNullString());
+        methodConfig.setMock(true);
+        assertThat(methodConfig.getMock(), equalTo("true"));
+        methodConfig.setMock("return null");
+        assertThat(methodConfig.getMock(), equalTo("return null"));
+        methodConfig.setMock("mock");
+        assertThat(methodConfig.getMock(), equalTo("mock"));
+    }
+
+    @Test
+    public void testMerger() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setMerger("merger");
+        assertThat(methodConfig.getMerger(), equalTo("merger"));
+    }
+
+    @Test
+    public void testCache() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setCache("cache");
+        assertThat(methodConfig.getCache(), equalTo("cache"));
+    }
+
+    @Test
+    public void testValidation() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setValidation("validation");
+        assertThat(methodConfig.getValidation(), equalTo("validation"));
+    }
+
+    @Test
+    public void testParameters() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("key", "value");
+        methodConfig.setParameters(parameters);
+        assertThat(methodConfig.getParameters(), sameInstance(parameters));
+    }
+
+    private static class MethodConfig extends AbstractMethodConfig {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java
new file mode 100644
index 0000000..2966322
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java
@@ -0,0 +1,212 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.remoting.Constants;
+import org.apache.dubbo.rpc.cluster.RouterFactory;
+import org.apache.dubbo.rpc.cluster.router.condition.ConditionRouterFactory;
+import org.apache.dubbo.rpc.cluster.router.condition.config.AppRouterFactory;
+import org.apache.dubbo.rpc.cluster.router.tag.TagRouterFactory;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;
+import static org.apache.dubbo.common.constants.CommonConstants.INVOKER_LISTENER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.REFERENCE_FILTER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.STUB_EVENT_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.CLUSTER_STICKY_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.ROUTER_KEY;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.hasValue;
+import static org.hamcrest.Matchers.is;
+import static org.mockito.Mockito.mock;
+import static org.mockito.Mockito.when;
+
+public class AbstractReferenceConfigTest {
+
+    @Test
+    public void testCheck() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setCheck(true);
+        assertThat(referenceConfig.isCheck(), is(true));
+    }
+
+    @Test
+    public void testInit() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setInit(true);
+        assertThat(referenceConfig.isInit(), is(true));
+    }
+
+    @Test
+    public void testGeneric() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setGeneric(true);
+        assertThat(referenceConfig.isGeneric(), is(true));
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        // FIXME: not sure why AbstractReferenceConfig has both isGeneric and getGeneric
+        assertThat(parameters, hasKey("generic"));
+    }
+
+    @Test
+    public void testInjvm() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setInit(true);
+        assertThat(referenceConfig.isInit(), is(true));
+    }
+
+    @Test
+    public void testFilter() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setFilter("mockfilter");
+        assertThat(referenceConfig.getFilter(), equalTo("mockfilter"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(REFERENCE_FILTER_KEY, "prefilter");
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(parameters, hasValue("prefilter,mockfilter"));
+    }
+
+    @Test
+    public void testRouter() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setRouter("condition");
+        assertThat(referenceConfig.getRouter(), equalTo("condition"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(ROUTER_KEY, "tag");
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(parameters, hasValue("tag,condition"));
+        URL url = mock(URL.class);
+        when(url.getParameter(ROUTER_KEY)).thenReturn("condition");
+        List<RouterFactory> routerFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class).getActivateExtension(url, ROUTER_KEY);
+        assertThat(routerFactories.stream().anyMatch(routerFactory -> routerFactory.getClass().equals(ConditionRouterFactory.class)), is(true));
+        when(url.getParameter(ROUTER_KEY)).thenReturn("-tag,-app");
+        routerFactories = ExtensionLoader.getExtensionLoader(RouterFactory.class).getActivateExtension(url, ROUTER_KEY);
+        assertThat(routerFactories.stream()
+                .allMatch(routerFactory -> !routerFactory.getClass().equals(TagRouterFactory.class)
+                        && !routerFactory.getClass().equals(AppRouterFactory.class)), is(true));
+    }
+
+    @Test
+    public void testListener() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setListener("mockinvokerlistener");
+        assertThat(referenceConfig.getListener(), equalTo("mockinvokerlistener"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(INVOKER_LISTENER_KEY, "prelistener");
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(parameters, hasValue("prelistener,mockinvokerlistener"));
+    }
+
+    @Test
+    public void testLazy() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setLazy(true);
+        assertThat(referenceConfig.getLazy(), is(true));
+    }
+
+    @Test
+    public void testOnconnect() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setOnconnect("onConnect");
+        assertThat(referenceConfig.getOnconnect(), equalTo("onConnect"));
+        assertThat(referenceConfig.getStubevent(), is(true));
+    }
+
+    @Test
+    public void testOndisconnect() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setOndisconnect("onDisconnect");
+        assertThat(referenceConfig.getOndisconnect(), equalTo("onDisconnect"));
+        assertThat(referenceConfig.getStubevent(), is(true));
+    }
+
+    @Test
+    public void testStubevent() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setOnconnect("onConnect");
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(parameters, hasKey(STUB_EVENT_KEY));
+    }
+
+    @Test
+    public void testReconnect() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setReconnect("reconnect");
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(referenceConfig.getReconnect(), equalTo("reconnect"));
+        assertThat(parameters, hasKey(Constants.RECONNECT_KEY));
+    }
+
+    @Test
+    public void testSticky() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setSticky(true);
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(referenceConfig.getSticky(), is(true));
+        assertThat(parameters, hasKey(CLUSTER_STICKY_KEY));
+    }
+
+    @Test
+    public void testVersion() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setVersion("version");
+        assertThat(referenceConfig.getVersion(), equalTo("version"));
+    }
+
+    @Test
+    public void testGroup() throws Exception {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setGroup("group");
+        assertThat(referenceConfig.getGroup(), equalTo("group"));
+    }
+
+    @Test
+    public void testGenericOverride() {
+        ReferenceConfig referenceConfig = new ReferenceConfig();
+        referenceConfig.setGeneric("false");
+        referenceConfig.refresh();
+        Assertions.assertFalse(referenceConfig.isGeneric());
+        Assertions.assertEquals("false", referenceConfig.getGeneric());
+
+        ReferenceConfig referenceConfig1 = new ReferenceConfig();
+        referenceConfig1.setGeneric(GENERIC_SERIALIZATION_NATIVE_JAVA);
+        referenceConfig1.refresh();
+        Assertions.assertEquals(GENERIC_SERIALIZATION_NATIVE_JAVA, referenceConfig1.getGeneric());
+        Assertions.assertTrue(referenceConfig1.isGeneric());
+
+        ReferenceConfig referenceConfig2 = new ReferenceConfig();
+        referenceConfig2.refresh();
+        Assertions.assertNull(referenceConfig2.getGeneric());
+    }
+
+    private static class ReferenceConfig extends AbstractReferenceConfig {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java
new file mode 100644
index 0000000..bd0e7cd
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java
@@ -0,0 +1,184 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+
+import org.junit.jupiter.api.Test;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.CommonConstants.EXPORTER_LISTENER_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SERVICE_FILTER_KEY;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasSize;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.notNullValue;
+import static org.hamcrest.Matchers.nullValue;
+
+public class AbstractServiceConfigTest {
+    @Test
+    public void testVersion() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setVersion("version");
+        assertThat(serviceConfig.getVersion(), equalTo("version"));
+    }
+
+    @Test
+    public void testGroup() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setGroup("group");
+        assertThat(serviceConfig.getGroup(), equalTo("group"));
+    }
+
+    @Test
+    public void testDelay() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setDelay(1000);
+        assertThat(serviceConfig.getDelay(), equalTo(1000));
+    }
+
+    @Test
+    public void testExport() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setExport(true);
+        assertThat(serviceConfig.getExport(), is(true));
+    }
+
+    @Test
+    public void testWeight() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setWeight(500);
+        assertThat(serviceConfig.getWeight(), equalTo(500));
+    }
+
+    @Test
+    public void testDocument() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setDocument("http://dubbo.apache.org");
+        assertThat(serviceConfig.getDocument(), equalTo("http://dubbo.apache.org"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractServiceConfig.appendParameters(parameters, serviceConfig);
+        assertThat(parameters, hasEntry("document", "http%3A%2F%2Fdubbo.apache.org"));
+    }
+
+    @Test
+    public void testToken() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setToken("token");
+        assertThat(serviceConfig.getToken(), equalTo("token"));
+        serviceConfig.setToken((Boolean) null);
+        assertThat(serviceConfig.getToken(), nullValue());
+        serviceConfig.setToken(true);
+        assertThat(serviceConfig.getToken(), is("true"));
+    }
+
+    @Test
+    public void testDeprecated() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setDeprecated(true);
+        assertThat(serviceConfig.isDeprecated(), is(true));
+    }
+
+    @Test
+    public void testDynamic() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setDynamic(true);
+        assertThat(serviceConfig.isDynamic(), is(true));
+    }
+
+    @Test
+    public void testProtocol() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        assertThat(serviceConfig.getProtocol(), nullValue());
+        serviceConfig.setProtocol(new ProtocolConfig());
+        assertThat(serviceConfig.getProtocol(), notNullValue());
+        serviceConfig.setProtocols(new ArrayList<>(Collections.singletonList(new ProtocolConfig())));
+        assertThat(serviceConfig.getProtocols(), hasSize(1));
+    }
+
+    @Test
+    public void testAccesslog() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setAccesslog("access.log");
+        assertThat(serviceConfig.getAccesslog(), equalTo("access.log"));
+        serviceConfig.setAccesslog((Boolean) null);
+        assertThat(serviceConfig.getAccesslog(), nullValue());
+        serviceConfig.setAccesslog(true);
+        assertThat(serviceConfig.getAccesslog(), equalTo("true"));
+    }
+
+    @Test
+    public void testExecutes() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setExecutes(10);
+        assertThat(serviceConfig.getExecutes(), equalTo(10));
+    }
+
+    @Test
+    public void testFilter() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setFilter("mockfilter");
+        assertThat(serviceConfig.getFilter(), equalTo("mockfilter"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(SERVICE_FILTER_KEY, "prefilter");
+        AbstractServiceConfig.appendParameters(parameters, serviceConfig);
+        assertThat(parameters, hasEntry(SERVICE_FILTER_KEY, "prefilter,mockfilter"));
+    }
+
+    @Test
+    public void testListener() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setListener("mockexporterlistener");
+        assertThat(serviceConfig.getListener(), equalTo("mockexporterlistener"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put(EXPORTER_LISTENER_KEY, "prelistener");
+        AbstractServiceConfig.appendParameters(parameters, serviceConfig);
+        assertThat(parameters, hasEntry(EXPORTER_LISTENER_KEY, "prelistener,mockexporterlistener"));
+    }
+
+    @Test
+    public void testRegister() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setRegister(true);
+        assertThat(serviceConfig.isRegister(), is(true));
+    }
+
+    @Test
+    public void testWarmup() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setWarmup(100);
+        assertThat(serviceConfig.getWarmup(), equalTo(100));
+    }
+
+    @Test
+    public void testSerialization() throws Exception {
+        ServiceConfig serviceConfig = new ServiceConfig();
+        serviceConfig.setSerialization("serialization");
+        assertThat(serviceConfig.getSerialization(), equalTo("serialization"));
+    }
+
+
+    private static class ServiceConfig extends AbstractServiceConfig {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ApplicationConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ApplicationConfigTest.java
new file mode 100644
index 0000000..f7ff994
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ApplicationConfigTest.java
@@ -0,0 +1,217 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.DUMP_DIRECTORY;
+import static org.apache.dubbo.common.constants.QosConstants.ACCEPT_FOREIGN_IP;
+import static org.apache.dubbo.common.constants.QosConstants.QOS_ENABLE;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.hamcrest.collection.IsCollectionWithSize.hasSize;
+
+public class ApplicationConfigTest {
+    @Test
+    public void testName() throws Exception {
+        ApplicationConfig application = new ApplicationConfig();
+        application.setName("app");
+        assertThat(application.getName(), equalTo("app"));
+        application = new ApplicationConfig("app2");
+        assertThat(application.getName(), equalTo("app2"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ApplicationConfig.appendParameters(parameters, application);
+        assertThat(parameters, hasEntry(APPLICATION_KEY, "app2"));
+    }
+
+    @Test
+    public void testVersion() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setVersion("1.0.0");
+        assertThat(application.getVersion(), equalTo("1.0.0"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ApplicationConfig.appendParameters(parameters, application);
+        assertThat(parameters, hasEntry("application.version", "1.0.0"));
+    }
+
+    @Test
+    public void testOwner() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setOwner("owner");
+        assertThat(application.getOwner(), equalTo("owner"));
+    }
+
+    @Test
+    public void testOrganization() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setOrganization("org");
+        assertThat(application.getOrganization(), equalTo("org"));
+    }
+
+    @Test
+    public void testArchitecture() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setArchitecture("arch");
+        assertThat(application.getArchitecture(), equalTo("arch"));
+    }
+
+    @Test
+    public void testEnvironment1() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setEnvironment("develop");
+        assertThat(application.getEnvironment(), equalTo("develop"));
+        application.setEnvironment("test");
+        assertThat(application.getEnvironment(), equalTo("test"));
+        application.setEnvironment("product");
+        assertThat(application.getEnvironment(), equalTo("product"));
+    }
+
+    @Test
+    public void testEnvironment2() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            ApplicationConfig application = new ApplicationConfig("app");
+            application.setEnvironment("illegal-env");
+        });
+    }
+
+    @Test
+    public void testRegistry() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        RegistryConfig registry = new RegistryConfig();
+        application.setRegistry(registry);
+        assertThat(application.getRegistry(), sameInstance(registry));
+        application.setRegistries(Collections.singletonList(registry));
+        assertThat(application.getRegistries(), contains(registry));
+        assertThat(application.getRegistries(), hasSize(1));
+    }
+
+    @Test
+    public void testMonitor() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setMonitor(new MonitorConfig("monitor-addr"));
+        assertThat(application.getMonitor().getAddress(), equalTo("monitor-addr"));
+        application.setMonitor("monitor-addr");
+        assertThat(application.getMonitor().getAddress(), equalTo("monitor-addr"));
+    }
+
+    @Test
+    public void testLogger() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setLogger("log4j");
+        assertThat(application.getLogger(), equalTo("log4j"));
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setDefault(true);
+        assertThat(application.isDefault(), is(true));
+    }
+
+    @Test
+    public void testDumpDirectory() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setDumpDirectory("/dump");
+        assertThat(application.getDumpDirectory(), equalTo("/dump"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ApplicationConfig.appendParameters(parameters, application);
+        assertThat(parameters, hasEntry(DUMP_DIRECTORY, "/dump"));
+    }
+
+    @Test
+    public void testQosEnable() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setQosEnable(true);
+        assertThat(application.getQosEnable(), is(true));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ApplicationConfig.appendParameters(parameters, application);
+        assertThat(parameters, hasEntry(QOS_ENABLE, "true"));
+    }
+
+    @Test
+    public void testQosPort() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setQosPort(8080);
+        assertThat(application.getQosPort(), equalTo(8080));
+    }
+
+    @Test
+    public void testQosAcceptForeignIp() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setQosAcceptForeignIp(true);
+        assertThat(application.getQosAcceptForeignIp(), is(true));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ApplicationConfig.appendParameters(parameters, application);
+        assertThat(parameters, hasEntry(ACCEPT_FOREIGN_IP, "true"));
+    }
+
+    @Test
+    public void testParameters() throws Exception {
+        ApplicationConfig application = new ApplicationConfig("app");
+        application.setQosAcceptForeignIp(true);
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("k1", "v1");
+        ApplicationConfig.appendParameters(parameters, application);
+        assertThat(parameters, hasEntry("k1", "v1"));
+        assertThat(parameters, hasEntry(ACCEPT_FOREIGN_IP, "true"));
+    }
+
+    @Test
+    public void testAppendEnvironmentProperties() {
+        try {
+            ApplicationConfig application = new ApplicationConfig("app");
+            System.setProperty("dubbo.labels", "tag1=value1;tag2=value2 ; tag3 = value3");
+            application.refresh();
+            Map<String, String> parameters = application.getParameters();
+            Assertions.assertEquals("value1", parameters.get("tag1"));
+            Assertions.assertEquals("value2", parameters.get("tag2"));
+            Assertions.assertEquals("value3", parameters.get("tag3"));
+
+            ApplicationConfig application1 = new ApplicationConfig("app");
+            System.setProperty("dubbo.env.keys", "tag1, tag2,tag3");
+            // mock environment variables
+            System.setProperty("tag1", "value1");
+            System.setProperty("tag2", "value2");
+            System.setProperty("tag3", "value3");
+            application1.refresh();
+            Map<String, String> parameters1 = application1.getParameters();
+            Assertions.assertEquals("value1", parameters1.get("tag1"));
+            Assertions.assertEquals("value2", parameters1.get("tag2"));
+            Assertions.assertEquals("value3", parameters1.get("tag3"));
+
+            Map<String, String> urlParameters = new HashMap<>();
+            ApplicationConfig.appendParameters(urlParameters, application1);
+            Assertions.assertEquals("value1", urlParameters.get("tag1"));
+            Assertions.assertEquals("value2", urlParameters.get("tag2"));
+            Assertions.assertEquals("value3", urlParameters.get("tag3"));
+        } finally {
+            System.clearProperty("dubbo.labels");
+            System.clearProperty("dubbo.keys");
+        }
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ArgumentConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ArgumentConfigTest.java
new file mode 100644
index 0000000..0fff22d
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ArgumentConfigTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+
+public class ArgumentConfigTest {
+    @Test
+    public void testIndex() throws Exception {
+        ArgumentConfig argument = new ArgumentConfig();
+        argument.setIndex(1);
+        assertThat(argument.getIndex(), is(1));
+    }
+
+    @Test
+    public void testType() throws Exception {
+        ArgumentConfig argument = new ArgumentConfig();
+        argument.setType("int");
+        assertThat(argument.getType(), equalTo("int"));
+    }
+
+    @Test
+    public void testCallback() throws Exception {
+        ArgumentConfig argument = new ArgumentConfig();
+        argument.setCallback(true);
+        assertThat(argument.isCallback(), is(true));
+    }
+
+    @Test
+    public void testArguments() throws Exception {
+        ArgumentConfig argument = new ArgumentConfig();
+        argument.setIndex(1);
+        argument.setType("int");
+        argument.setCallback(true);
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractServiceConfig.appendParameters(parameters, argument);
+        assertThat(parameters, hasEntry("callback", "true"));
+        assertThat(parameters.size(), is(1));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java
new file mode 100644
index 0000000..fcba6fa
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ConfigCenterConfigTest.java
@@ -0,0 +1,44 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+public class ConfigCenterConfigTest {
+    @Test
+    public void testPrefix() {
+        ConfigCenterConfig config = new ConfigCenterConfig();
+        Assertions.assertEquals("dubbo.config-center", config.getPrefix());
+    }
+
+    @Test
+    public void testToUrl() {
+        ConfigCenterConfig config = new ConfigCenterConfig();
+        config.setNamespace("namespace");
+        config.setGroup("group");
+        config.setAddress("zookeeper://127.0.0.1:2181");
+
+        Assertions.assertEquals("zookeeper://127.0.0.1:2181/ConfigCenterConfig?check=true&" +
+                        "config-file=dubbo.properties&group=group&highest-priority=true&" +
+                        "namespace=namespace&timeout=3000",
+                config.toUrl().toFullString()
+        );
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
new file mode 100644
index 0000000..49be546
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
@@ -0,0 +1,81 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+
+public class ConsumerConfigTest {
+    @Test
+    public void testTimeout() throws Exception {
+        try {
+            System.clearProperty("sun.rmi.transport.tcp.responseTimeout");
+            ConsumerConfig consumer = new ConsumerConfig();
+            consumer.setTimeout(10);
+            assertThat(consumer.getTimeout(), is(10));
+            assertThat(System.getProperty("sun.rmi.transport.tcp.responseTimeout"), equalTo("10"));
+        } finally {
+            System.clearProperty("sun.rmi.transport.tcp.responseTimeout");
+        }
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        ConsumerConfig consumer = new ConsumerConfig();
+        consumer.setDefault(true);
+        assertThat(consumer.isDefault(), is(true));
+    }
+
+    @Test
+    public void testClient() throws Exception {
+        ConsumerConfig consumer = new ConsumerConfig();
+        consumer.setClient("client");
+        assertThat(consumer.getClient(), equalTo("client"));
+    }
+
+    @Test
+    public void testThreadpool() throws Exception {
+        ConsumerConfig consumer = new ConsumerConfig();
+        consumer.setThreadpool("fixed");
+        assertThat(consumer.getThreadpool(), equalTo("fixed"));
+    }
+
+    @Test
+    public void testCorethreads() throws Exception {
+        ConsumerConfig consumer = new ConsumerConfig();
+        consumer.setCorethreads(10);
+        assertThat(consumer.getCorethreads(), equalTo(10));
+    }
+
+    @Test
+    public void testThreads() throws Exception {
+        ConsumerConfig consumer = new ConsumerConfig();
+        consumer.setThreads(20);
+        assertThat(consumer.getThreads(), equalTo(20));
+    }
+
+    @Test
+    public void testQueues() throws Exception {
+        ConsumerConfig consumer = new ConsumerConfig();
+        consumer.setQueues(5);
+        assertThat(consumer.getQueues(), equalTo(5));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/MethodConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/MethodConfigTest.java
new file mode 100644
index 0000000..b190d5c
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/MethodConfigTest.java
@@ -0,0 +1,240 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.config.annotation.Argument;
+import org.apache.dubbo.config.annotation.Method;
+import org.apache.dubbo.config.annotation.Reference;
+
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import static org.apache.dubbo.config.Constants.ON_INVOKE_INSTANCE_KEY;
+import static org.apache.dubbo.config.Constants.ON_INVOKE_METHOD_KEY;
+import static org.apache.dubbo.config.Constants.ON_RETURN_INSTANCE_KEY;
+import static org.apache.dubbo.config.Constants.ON_RETURN_METHOD_KEY;
+import static org.apache.dubbo.config.Constants.ON_THROW_INSTANCE_KEY;
+import static org.apache.dubbo.config.Constants.ON_THROW_METHOD_KEY;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+
+public class MethodConfigTest {
+    private static final String METHOD_NAME = "sayHello";
+    private static final int TIMEOUT = 1300;
+    private static final int RETRIES = 4;
+    private static final String LOADBALANCE = "random";
+    private static final boolean ASYNC = true;
+    private static final int ACTIVES = 3;
+    private static final int EXECUTES = 5;
+    private static final boolean DEPERECATED = true;
+    private static final boolean STICKY = true;
+    private static final String ONINVOKE = "i";
+    private static final String ONTHROW = "t";
+    private static final String ONRETURN = "r";
+    private static final String CACHE = "c";
+    private static final String VALIDATION = "v";
+    private static final int ARGUMENTS_INDEX = 24;
+    private static final boolean ARGUMENTS_CALLBACK = true;
+    private static final String ARGUMENTS_TYPE = "sss";
+
+    @Reference(methods = {@Method(name = METHOD_NAME, timeout = TIMEOUT, retries = RETRIES, loadbalance = LOADBALANCE, async = ASYNC,
+            actives = ACTIVES, executes = EXECUTES, deprecated = DEPERECATED, sticky = STICKY, oninvoke = ONINVOKE, onthrow = ONTHROW, onreturn = ONRETURN, cache = CACHE, validation = VALIDATION,
+            arguments = {@Argument(index = ARGUMENTS_INDEX, callback = ARGUMENTS_CALLBACK, type = ARGUMENTS_TYPE)})})
+    private String testField;
+
+    @Test
+    public void testStaticConstructor() throws NoSuchFieldException {
+        Method[] methods = this.getClass().getDeclaredField("testField").getAnnotation(Reference.class).methods();
+        List<MethodConfig> methodConfigs = MethodConfig.constructMethodConfig(methods);
+        MethodConfig methodConfig = methodConfigs.get(0);
+
+        assertThat(METHOD_NAME, equalTo(methodConfig.getName()));
+        assertThat(TIMEOUT, equalTo(methodConfig.getTimeout().intValue()));
+        assertThat(RETRIES, equalTo(methodConfig.getRetries().intValue()));
+        assertThat(LOADBALANCE, equalTo(methodConfig.getLoadbalance()));
+        assertThat(ASYNC, equalTo(methodConfig.isAsync()));
+        assertThat(ACTIVES, equalTo(methodConfig.getActives().intValue()));
+        assertThat(EXECUTES, equalTo(methodConfig.getExecutes().intValue()));
+        assertThat(DEPERECATED, equalTo(methodConfig.getDeprecated()));
+        assertThat(STICKY, equalTo(methodConfig.getSticky()));
+        assertThat(ONINVOKE, equalTo(methodConfig.getOninvoke()));
+        assertThat(ONTHROW, equalTo(methodConfig.getOnthrow()));
+        assertThat(ONRETURN, equalTo(methodConfig.getOnreturn()));
+        assertThat(CACHE, equalTo(methodConfig.getCache()));
+        assertThat(VALIDATION, equalTo(methodConfig.getValidation()));
+        assertThat(ARGUMENTS_INDEX, equalTo(methodConfig.getArguments().get(0).getIndex().intValue()));
+        assertThat(ARGUMENTS_CALLBACK, equalTo(methodConfig.getArguments().get(0).isCallback()));
+        assertThat(ARGUMENTS_TYPE, equalTo(methodConfig.getArguments().get(0).getType()));
+    }
+
+    @Test
+    public void testName() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setName("hello");
+        assertThat(method.getName(), equalTo("hello"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters, not(hasKey("name")));
+    }
+
+    @Test
+    public void testStat() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setStat(10);
+        assertThat(method.getStat(), equalTo(10));
+    }
+
+    @Test
+    public void testRetry() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setRetry(true);
+        assertThat(method.isRetry(), is(true));
+    }
+
+    @Test
+    public void testReliable() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setReliable(true);
+        assertThat(method.isReliable(), is(true));
+    }
+
+    @Test
+    public void testExecutes() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setExecutes(10);
+        assertThat(method.getExecutes(), equalTo(10));
+    }
+
+    @Test
+    public void testDeprecated() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setDeprecated(true);
+        assertThat(method.getDeprecated(), is(true));
+    }
+
+    @Test
+    public void testArguments() throws Exception {
+        MethodConfig method = new MethodConfig();
+        ArgumentConfig argument = new ArgumentConfig();
+        method.setArguments(Collections.singletonList(argument));
+        assertThat(method.getArguments(), contains(argument));
+        assertThat(method.getArguments(), Matchers.<ArgumentConfig>hasSize(1));
+    }
+
+    @Test
+    public void testSticky() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setSticky(true);
+        assertThat(method.getSticky(), is(true));
+    }
+
+    @Test
+    public void testOnreturn() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setOnreturn("on-return-object");
+        assertThat(method.getOnreturn(), equalTo((Object) "on-return-object"));
+        Map<String, Object> attribute = new HashMap<String, Object>();
+        MethodConfig.appendAttributes(attribute, method);
+        assertThat(attribute, hasEntry((Object) ON_RETURN_INSTANCE_KEY, (Object) "on-return-object"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters.size(), is(0));
+    }
+
+    @Test
+    public void testOnreturnMethod() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setOnreturnMethod("on-return-method");
+        assertThat(method.getOnreturnMethod(), equalTo("on-return-method"));
+        Map<String, Object> attribute = new HashMap<String, Object>();
+        MethodConfig.appendAttributes(attribute, method);
+        assertThat(attribute, hasEntry((Object) ON_RETURN_METHOD_KEY, (Object) "on-return-method"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters.size(), is(0));
+    }
+
+    @Test
+    public void testOnthrow() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setOnthrow("on-throw-object");
+        assertThat(method.getOnthrow(), equalTo((Object) "on-throw-object"));
+        Map<String, Object> attribute = new HashMap<String, Object>();
+        MethodConfig.appendAttributes(attribute, method);
+        assertThat(attribute, hasEntry((Object) ON_THROW_INSTANCE_KEY, (Object) "on-throw-object"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters.size(), is(0));
+    }
+
+    @Test
+    public void testOnthrowMethod() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setOnthrowMethod("on-throw-method");
+        assertThat(method.getOnthrowMethod(), equalTo("on-throw-method"));
+        Map<String, Object> attribute = new HashMap<String, Object>();
+        MethodConfig.appendAttributes(attribute, method);
+        assertThat(attribute, hasEntry((Object) ON_THROW_METHOD_KEY, (Object) "on-throw-method"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters.size(), is(0));
+    }
+
+    @Test
+    public void testOninvoke() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setOninvoke("on-invoke-object");
+        assertThat(method.getOninvoke(), equalTo((Object) "on-invoke-object"));
+        Map<String, Object> attribute = new HashMap<String, Object>();
+        MethodConfig.appendAttributes(attribute, method);
+        assertThat(attribute, hasEntry((Object) ON_INVOKE_INSTANCE_KEY, (Object) "on-invoke-object"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters.size(), is(0));
+    }
+
+    @Test
+    public void testOninvokeMethod() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setOninvokeMethod("on-invoke-method");
+        assertThat(method.getOninvokeMethod(), equalTo("on-invoke-method"));
+        Map<String, Object> attribute = new HashMap<String, Object>();
+        MethodConfig.appendAttributes(attribute, method);
+        assertThat(attribute, hasEntry((Object) ON_INVOKE_METHOD_KEY, (Object) "on-invoke-method"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MethodConfig.appendParameters(parameters, method);
+        assertThat(parameters.size(), is(0));
+    }
+
+    @Test
+    public void testReturn() throws Exception {
+        MethodConfig method = new MethodConfig();
+        method.setReturn(true);
+        assertThat(method.isReturn(), is(true));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ModuleConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ModuleConfigTest.java
new file mode 100644
index 0000000..a5977cb
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ModuleConfigTest.java
@@ -0,0 +1,104 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.hamcrest.Matchers;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.contains;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.sameInstance;
+
+public class ModuleConfigTest {
+
+    @Test
+    public void testName2() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        module.setName("module-name");
+        assertThat(module.getName(), equalTo("module-name"));
+        assertThat(module.getId(), equalTo("module-name"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ModuleConfig.appendParameters(parameters, module);
+        assertThat(parameters, hasEntry("module", "module-name"));
+    }
+
+    @Test
+    public void testVersion() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        module.setName("module-name");
+        module.setVersion("1.0.0");
+        assertThat(module.getVersion(), equalTo("1.0.0"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        ModuleConfig.appendParameters(parameters, module);
+        assertThat(parameters, hasEntry("module.version", "1.0.0"));
+    }
+
+    @Test
+    public void testOwner() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        module.setOwner("owner");
+        assertThat(module.getOwner(), equalTo("owner"));
+    }
+
+    @Test
+    public void testOrganization() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        module.setOrganization("org");
+        assertThat(module.getOrganization(), equalTo("org"));
+    }
+
+    @Test
+    public void testRegistry() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        RegistryConfig registry = new RegistryConfig();
+        module.setRegistry(registry);
+        assertThat(module.getRegistry(), sameInstance(registry));
+    }
+
+    @Test
+    public void testRegistries() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        RegistryConfig registry = new RegistryConfig();
+        module.setRegistries(Collections.singletonList(registry));
+        assertThat(module.getRegistries(), Matchers.<RegistryConfig>hasSize(1));
+        assertThat(module.getRegistries(), contains(registry));
+    }
+
+    @Test
+    public void testMonitor() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        module.setMonitor("monitor-addr1");
+        assertThat(module.getMonitor().getAddress(), equalTo("monitor-addr1"));
+        module.setMonitor(new MonitorConfig("monitor-addr2"));
+        assertThat(module.getMonitor().getAddress(), equalTo("monitor-addr2"));
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        module.setDefault(true);
+        assertThat(module.isDefault(), is(true));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/MonitorConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/MonitorConfigTest.java
new file mode 100644
index 0000000..60dd40a
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/MonitorConfigTest.java
@@ -0,0 +1,107 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+
+public class MonitorConfigTest {
+    @Test
+    public void testAddress() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setAddress("monitor-addr");
+        assertThat(monitor.getAddress(), equalTo("monitor-addr"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MonitorConfig.appendParameters(parameters, monitor);
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testProtocol() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setProtocol("protocol");
+        assertThat(monitor.getProtocol(), equalTo("protocol"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MonitorConfig.appendParameters(parameters, monitor);
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testUsername() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setUsername("user");
+        assertThat(monitor.getUsername(), equalTo("user"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MonitorConfig.appendParameters(parameters, monitor);
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testPassword() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setPassword("secret");
+        assertThat(monitor.getPassword(), equalTo("secret"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        MonitorConfig.appendParameters(parameters, monitor);
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testGroup() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setGroup("group");
+        assertThat(monitor.getGroup(), equalTo("group"));
+    }
+
+    @Test
+    public void testVersion() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setVersion("1.0.0");
+        assertThat(monitor.getVersion(), equalTo("1.0.0"));
+    }
+
+    @Test
+    public void testParameters() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        Map<String, String> parameters = Collections.singletonMap("k1", "v1");
+        monitor.setParameters(parameters);
+        assertThat(monitor.getParameters(), hasEntry("k1", "v1"));
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setDefault(true);
+        assertThat(monitor.isDefault(), is(true));
+    }
+
+    @Test
+    public void testInterval() throws Exception {
+        MonitorConfig monitor = new MonitorConfig();
+        monitor.setInterval("100");
+        assertThat(monitor.getInterval(), equalTo("100"));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ProtocolConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ProtocolConfigTest.java
new file mode 100644
index 0000000..3a66608
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ProtocolConfigTest.java
@@ -0,0 +1,204 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+
+public class ProtocolConfigTest {
+
+    @Test
+    public void testName() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setName("name");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProtocolConfig.appendParameters(parameters, protocol);
+        assertThat(protocol.getName(), equalTo("name"));
+        assertThat(protocol.getId(), equalTo("name"));
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testHost() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setHost("host");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProtocolConfig.appendParameters(parameters, protocol);
+        assertThat(protocol.getHost(), equalTo("host"));
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testPort() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setPort(8080);
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProtocolConfig.appendParameters(parameters, protocol);
+        assertThat(protocol.getPort(), equalTo(8080));
+        assertThat(parameters.isEmpty(), is(true));
+    }
+
+    @Test
+    public void testPath() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setContextpath("context-path");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProtocolConfig.appendParameters(parameters, protocol);
+        assertThat(protocol.getPath(), equalTo("context-path"));
+        assertThat(protocol.getContextpath(), equalTo("context-path"));
+        assertThat(parameters.isEmpty(), is(true));
+        protocol.setPath("path");
+        assertThat(protocol.getPath(), equalTo("path"));
+        assertThat(protocol.getContextpath(), equalTo("path"));
+    }
+
+    @Test
+    public void testCorethreads() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setCorethreads(10);
+        assertThat(protocol.getCorethreads(), is(10));
+    }
+
+    @Test
+    public void testThreads() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setThreads(10);
+        assertThat(protocol.getThreads(), is(10));
+    }
+
+    @Test
+    public void testIothreads() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setIothreads(10);
+        assertThat(protocol.getIothreads(), is(10));
+    }
+
+    @Test
+    public void testQueues() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setQueues(10);
+        assertThat(protocol.getQueues(), is(10));
+    }
+
+    @Test
+    public void testAccepts() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setAccepts(10);
+        assertThat(protocol.getAccepts(), is(10));
+    }
+
+    @Test
+    public void testCodec() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setName("dubbo");
+        protocol.setCodec("mockcodec");
+        assertThat(protocol.getCodec(), equalTo("mockcodec"));
+    }
+
+    @Test
+    public void testAccesslog() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setAccesslog("access.log");
+        assertThat(protocol.getAccesslog(), equalTo("access.log"));
+    }
+
+    @Test
+    public void testTelnet() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setTelnet("mocktelnethandler");
+        assertThat(protocol.getTelnet(), equalTo("mocktelnethandler"));
+    }
+
+    @Test
+    public void testRegister() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setRegister(true);
+        assertThat(protocol.isRegister(), is(true));
+    }
+
+    @Test
+    public void testTransporter() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setTransporter("mocktransporter");
+        assertThat(protocol.getTransporter(), equalTo("mocktransporter"));
+    }
+
+    @Test
+    public void testExchanger() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setExchanger("mockexchanger");
+        assertThat(protocol.getExchanger(), equalTo("mockexchanger"));
+    }
+
+    @Test
+    public void testDispatcher() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setDispatcher("mockdispatcher");
+        assertThat(protocol.getDispatcher(), equalTo("mockdispatcher"));
+    }
+
+    @Test
+    public void testNetworker() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setNetworker("networker");
+        assertThat(protocol.getNetworker(), equalTo("networker"));
+    }
+
+    @Test
+    public void testParameters() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setParameters(Collections.singletonMap("k1", "v1"));
+        assertThat(protocol.getParameters(), hasEntry("k1", "v1"));
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setDefault(true);
+        assertThat(protocol.isDefault(), is(true));
+    }
+
+    @Test
+    public void testKeepAlive() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setKeepAlive(true);
+        assertThat(protocol.getKeepAlive(), is(true));
+    }
+
+    @Test
+    public void testOptimizer() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setOptimizer("optimizer");
+        assertThat(protocol.getOptimizer(), equalTo("optimizer"));
+    }
+
+    @Test
+    public void testExtension() throws Exception {
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setExtension("extension");
+        assertThat(protocol.getExtension(), equalTo("extension"));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ProviderConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ProviderConfigTest.java
new file mode 100644
index 0000000..f76990f
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ProviderConfigTest.java
@@ -0,0 +1,219 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.not;
+
+public class ProviderConfigTest {
+    @Test
+    public void testProtocol() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setProtocol("protocol");
+        assertThat(provider.getProtocol().getName(), equalTo("protocol"));
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setDefault(true);
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProviderConfig.appendParameters(parameters, provider);
+        assertThat(provider.isDefault(), is(true));
+        assertThat(parameters, not(hasKey("default")));
+    }
+
+    @Test
+    public void testHost() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setHost("demo-host");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProviderConfig.appendParameters(parameters, provider);
+        assertThat(provider.getHost(), equalTo("demo-host"));
+        assertThat(parameters, not(hasKey("host")));
+    }
+
+    @Test
+    public void testPort() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setPort(8080);
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProviderConfig.appendParameters(parameters, provider);
+        assertThat(provider.getPort(), is(8080));
+        assertThat(parameters, not(hasKey("port")));
+    }
+
+    @Test
+    public void testPath() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setPath("/path");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProviderConfig.appendParameters(parameters, provider);
+        assertThat(provider.getPath(), equalTo("/path"));
+        assertThat(provider.getContextpath(), equalTo("/path"));
+        assertThat(parameters, not(hasKey("path")));
+    }
+
+    @Test
+    public void testContextPath() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setContextpath("/context-path");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProviderConfig.appendParameters(parameters, provider);
+        assertThat(provider.getContextpath(), equalTo("/context-path"));
+        assertThat(parameters, not(hasKey("/context-path")));
+    }
+
+    @Test
+    public void testThreadpool() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setThreadpool("mockthreadpool");
+        assertThat(provider.getThreadpool(), equalTo("mockthreadpool"));
+    }
+
+    @Test
+    public void testThreads() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setThreads(10);
+        assertThat(provider.getThreads(), is(10));
+    }
+
+    @Test
+    public void testIothreads() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setIothreads(10);
+        assertThat(provider.getIothreads(), is(10));
+    }
+
+    @Test
+    public void testQueues() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setQueues(10);
+        assertThat(provider.getQueues(), is(10));
+    }
+
+    @Test
+    public void testAccepts() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setAccepts(10);
+        assertThat(provider.getAccepts(), is(10));
+    }
+
+    @Test
+    public void testCharset() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setCharset("utf-8");
+        assertThat(provider.getCharset(), equalTo("utf-8"));
+    }
+
+    @Test
+    public void testPayload() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setPayload(10);
+        assertThat(provider.getPayload(), is(10));
+    }
+
+    @Test
+    public void testBuffer() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setBuffer(10);
+        assertThat(provider.getBuffer(), is(10));
+    }
+
+    @Test
+    public void testServer() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setServer("demo-server");
+        assertThat(provider.getServer(), equalTo("demo-server"));
+    }
+
+    @Test
+    public void testClient() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setClient("client");
+        assertThat(provider.getClient(), equalTo("client"));
+    }
+
+    @Test
+    public void testTelnet() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setTelnet("mocktelnethandler");
+        assertThat(provider.getTelnet(), equalTo("mocktelnethandler"));
+    }
+
+    @Test
+    public void testPrompt() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setPrompt("#");
+        Map<String, String> parameters = new HashMap<String, String>();
+        ProviderConfig.appendParameters(parameters, provider);
+        assertThat(provider.getPrompt(), equalTo("#"));
+        assertThat(parameters, hasEntry("prompt", "%23"));
+    }
+
+    @Test
+    public void testStatus() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setStatus("mockstatuschecker");
+        assertThat(provider.getStatus(), equalTo("mockstatuschecker"));
+    }
+
+    @Test
+    public void testTransporter() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setTransporter("mocktransporter");
+        assertThat(provider.getTransporter(), equalTo("mocktransporter"));
+    }
+
+    @Test
+    public void testExchanger() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setExchanger("mockexchanger");
+        assertThat(provider.getExchanger(), equalTo("mockexchanger"));
+    }
+
+    @Test
+    public void testDispatcher() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setDispatcher("mockdispatcher");
+        assertThat(provider.getDispatcher(), equalTo("mockdispatcher"));
+    }
+
+    @Test
+    public void testNetworker() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setNetworker("networker");
+        assertThat(provider.getNetworker(), equalTo("networker"));
+    }
+
+    @Test
+    public void testWait() throws Exception {
+        ProviderConfig provider = new ProviderConfig();
+        provider.setWait(10);
+        assertThat(provider.getWait(), equalTo(10));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
new file mode 100644
index 0000000..775596c
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -0,0 +1,159 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.config.annotation.Argument;
+import org.apache.dubbo.config.annotation.Method;
+import org.apache.dubbo.config.annotation.Reference;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.dubbo.rpc.Constants.LOCAL_PROTOCOL;
+
+public class ReferenceConfigTest {
+
+    @BeforeEach
+    public void setUp() {
+        ApplicationModel.reset();
+    }
+
+    @AfterEach
+    public void tearDown() {
+        ApplicationModel.reset();
+    }
+
+    @Test
+    public void testInjvm() throws Exception {
+        ApplicationConfig application = new ApplicationConfig();
+        application.setName("test-protocol-random-port");
+
+        RegistryConfig registry = new RegistryConfig();
+        registry.setAddress("multicast://224.5.6.7:1234");
+
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setName("mockprotocol");
+
+        ServiceConfig<DemoService> demoService;
+        demoService = new ServiceConfig<DemoService>();
+        demoService.setInterface(DemoService.class);
+        demoService.setRef(new DemoServiceImpl());
+        demoService.setApplication(application);
+        demoService.setRegistry(registry);
+        demoService.setProtocol(protocol);
+
+        ReferenceConfig<DemoService> rc = new ReferenceConfig<DemoService>();
+        rc.setApplication(application);
+        rc.setRegistry(registry);
+        rc.setInterface(DemoService.class.getName());
+        rc.setInjvm(false);
+
+        try {
+            System.setProperty("java.net.preferIPv4Stack", "true");
+            demoService.export();
+            rc.get();
+            Assertions.assertTrue(!LOCAL_PROTOCOL.equalsIgnoreCase(
+                    rc.getInvoker().getUrl().getProtocol()));
+        } finally {
+            System.clearProperty("java.net.preferIPv4Stack");
+            demoService.unexport();
+        }
+    }
+
+    /**
+     * unit test for dubbo-1765
+     */
+    @Test
+    public void testReferenceRetry() {
+        ApplicationConfig application = new ApplicationConfig();
+        application.setName("test-reference-retry");
+        RegistryConfig registry = new RegistryConfig();
+        registry.setAddress("multicast://224.5.6.7:1234");
+        ProtocolConfig protocol = new ProtocolConfig();
+        protocol.setName("mockprotocol");
+
+        ReferenceConfig<DemoService> rc = new ReferenceConfig<DemoService>();
+        rc.setApplication(application);
+        rc.setRegistry(registry);
+        rc.setInterface(DemoService.class.getName());
+
+        boolean success = false;
+        DemoService demoService = null;
+        try {
+            demoService = rc.get();
+            success = true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Assertions.assertFalse(success);
+        Assertions.assertNull(demoService);
+
+        ServiceConfig<DemoService> sc = new ServiceConfig<DemoService>();
+        sc.setInterface(DemoService.class);
+        sc.setRef(new DemoServiceImpl());
+        sc.setApplication(application);
+        sc.setRegistry(registry);
+        sc.setProtocol(protocol);
+
+        try {
+            System.setProperty("java.net.preferIPv4Stack", "true");
+            sc.export();
+            demoService = rc.get();
+            success = true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        } finally {
+            System.clearProperty("java.net.preferIPv4Stack");
+        }
+        Assertions.assertTrue(success);
+        Assertions.assertNotNull(demoService);
+
+    }
+
+    @Test
+    public void testConstructWithReferenceAnnotation() throws NoSuchFieldException {
+        Reference reference = getClass().getDeclaredField("innerTest").getAnnotation(Reference.class);
+        ReferenceConfig referenceConfig = new ReferenceConfig(reference);
+        Assertions.assertEquals(1, referenceConfig.getMethods().size());
+        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getName(), "sayHello");
+        Assertions.assertEquals(1300, (int) ((MethodConfig) referenceConfig.getMethods().get(0)).getTimeout());
+        Assertions.assertEquals(4, (int) ((MethodConfig) referenceConfig.getMethods().get(0)).getRetries());
+        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getLoadbalance(), "random");
+        Assertions.assertEquals(3, (int) ((MethodConfig) referenceConfig.getMethods().get(0)).getActives());
+        Assertions.assertEquals(5, (int) ((MethodConfig) referenceConfig.getMethods().get(0)).getExecutes());
+        Assertions.assertTrue(((MethodConfig) referenceConfig.getMethods().get(0)).isAsync());
+        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOninvoke(), "i");
+        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnreturn(), "r");
+        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getOnthrow(), "t");
+        Assertions.assertEquals(((MethodConfig) referenceConfig.getMethods().get(0)).getCache(), "c");
+    }
+
+
+    @Reference(methods = {@Method(name = "sayHello", timeout = 1300, retries = 4, loadbalance = "random", async = true,
+            actives = 3, executes = 5, deprecated = true, sticky = true, oninvoke = "i", onthrow = "t", onreturn = "r", cache = "c", validation = "v",
+            arguments = {@Argument(index = 24, callback = true, type = "sss")})})
+    private InnerTest innerTest;
+
+    private class InnerTest {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/RegistryConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/RegistryConfigTest.java
new file mode 100644
index 0000000..fb74b1e
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/RegistryConfigTest.java
@@ -0,0 +1,190 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+import static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.not;
+
+public class RegistryConfigTest {
+    @Test
+    public void testProtocol() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setProtocol("protocol");
+        assertThat(registry.getProtocol(), equalTo(registry.getProtocol()));
+    }
+
+    @Test
+    public void testAddress() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setAddress("localhost");
+        assertThat(registry.getAddress(), equalTo("localhost"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        RegistryConfig.appendParameters(parameters, registry);
+        assertThat(parameters, not(hasKey("address")));
+    }
+
+    @Test
+    public void testUsername() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setUsername("username");
+        assertThat(registry.getUsername(), equalTo("username"));
+    }
+
+    @Test
+    public void testPassword() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setPassword("password");
+        assertThat(registry.getPassword(), equalTo("password"));
+    }
+
+    @Test
+    public void testWait() throws Exception {
+        try {
+            RegistryConfig registry = new RegistryConfig();
+            registry.setWait(10);
+            assertThat(registry.getWait(), is(10));
+            assertThat(System.getProperty(SHUTDOWN_WAIT_KEY), equalTo("10"));
+        } finally {
+            System.clearProperty(SHUTDOWN_TIMEOUT_KEY);
+        }
+    }
+
+    @Test
+    public void testCheck() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setCheck(true);
+        assertThat(registry.isCheck(), is(true));
+    }
+
+    @Test
+    public void testFile() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setFile("file");
+        assertThat(registry.getFile(), equalTo("file"));
+    }
+
+    @Test
+    public void testTransporter() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setTransporter("transporter");
+        assertThat(registry.getTransporter(), equalTo("transporter"));
+    }
+
+    @Test
+    public void testClient() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setClient("client");
+        assertThat(registry.getClient(), equalTo("client"));
+    }
+
+    @Test
+    public void testTimeout() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setTimeout(10);
+        assertThat(registry.getTimeout(), is(10));
+    }
+
+    @Test
+    public void testSession() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setSession(10);
+        assertThat(registry.getSession(), is(10));
+    }
+
+    @Test
+    public void testDynamic() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setDynamic(true);
+        assertThat(registry.isDynamic(), is(true));
+    }
+
+    @Test
+    public void testRegister() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setRegister(true);
+        assertThat(registry.isRegister(), is(true));
+    }
+
+    @Test
+    public void testSubscribe() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setSubscribe(true);
+        assertThat(registry.isSubscribe(), is(true));
+    }
+
+    @Test
+    public void testCluster() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setCluster("cluster");
+        assertThat(registry.getCluster(), equalTo("cluster"));
+    }
+
+    @Test
+    public void testGroup() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setGroup("group");
+        assertThat(registry.getGroup(), equalTo("group"));
+    }
+
+    @Test
+    public void testVersion() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setVersion("1.0.0");
+        assertThat(registry.getVersion(), equalTo("1.0.0"));
+    }
+
+    @Test
+    public void testParameters() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setParameters(Collections.singletonMap("k1", "v1"));
+        assertThat(registry.getParameters(), hasEntry("k1", "v1"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        RegistryConfig.appendParameters(parameters, registry);
+        assertThat(parameters, hasEntry("k1", "v1"));
+    }
+
+    @Test
+    public void testDefault() throws Exception {
+        RegistryConfig registry = new RegistryConfig();
+        registry.setDefault(true);
+        assertThat(registry.isDefault(), is(true));
+    }
+
+    @Test
+    public void testEquals() throws Exception {
+        RegistryConfig registry1 = new RegistryConfig();
+        RegistryConfig registry2 = new RegistryConfig();
+        registry1.setAddress("zookeeper://127.0.0.1:2182");
+        registry2.setAddress("zookeeper://127.0.0.1:2183");
+        Assertions.assertNotEquals(registry1, registry2);
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java
new file mode 100644
index 0000000..4d157ff
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/ServiceConfigTest.java
@@ -0,0 +1,264 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.config.mock.MockProtocol2;
+import org.apache.dubbo.config.mock.MockRegistryFactory2;
+import org.apache.dubbo.config.mock.TestProxyFactory;
+import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.service.GenericService;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Disabled;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+import java.util.concurrent.TimeUnit;
+
+import static org.apache.dubbo.common.constants.CommonConstants.ANYHOST_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.APPLICATION_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_DEFAULT;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;
+import static org.apache.dubbo.common.constants.CommonConstants.INTERFACE_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.METHODS_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.PROVIDER;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SIDE_KEY;
+import static org.apache.dubbo.config.Constants.SHUTDOWN_TIMEOUT_KEY;
+import static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;
+import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;
+import static org.apache.dubbo.rpc.Constants.GENERIC_KEY;
+import static org.apache.dubbo.rpc.cluster.Constants.EXPORT_KEY;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+import static org.mockito.Mockito.withSettings;
+
+public class ServiceConfigTest {
+    private Protocol protocolDelegate = Mockito.mock(Protocol.class);
+    private Registry registryDelegate = Mockito.mock(Registry.class);
+    private Exporter exporter = Mockito.mock(Exporter.class);
+    private ServiceConfig<DemoServiceImpl> service = new ServiceConfig<DemoServiceImpl>();
+    private ServiceConfig<DemoServiceImpl> service2 = new ServiceConfig<DemoServiceImpl>();
+    private ServiceConfig<DemoServiceImpl> delayService = new ServiceConfig<DemoServiceImpl>();
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        MockProtocol2.delegate = protocolDelegate;
+        MockRegistryFactory2.registry = registryDelegate;
+        Mockito.when(protocolDelegate.export(Mockito.any(Invoker.class))).thenReturn(exporter);
+
+        ApplicationConfig app = new ApplicationConfig("app");
+
+        ProtocolConfig protocolConfig = new ProtocolConfig();
+        protocolConfig.setName("mockprotocol2");
+
+        ProviderConfig provider = new ProviderConfig();
+        provider.setExport(true);
+        provider.setProtocol(protocolConfig);
+
+        RegistryConfig registry = new RegistryConfig();
+        registry.setProtocol("mockprotocol2");
+        registry.setAddress("N/A");
+
+        ArgumentConfig argument = new ArgumentConfig();
+        argument.setIndex(0);
+        argument.setCallback(false);
+
+        MethodConfig method = new MethodConfig();
+        method.setName("echo");
+        method.setArguments(Collections.singletonList(argument));
+
+        service.setProvider(provider);
+        service.setApplication(app);
+        service.setRegistry(registry);
+        service.setInterface(DemoService.class);
+        service.setRef(new DemoServiceImpl());
+        service.setMethods(Collections.singletonList(method));
+
+        service2.setProvider(provider);
+        service2.setApplication(app);
+        service2.setRegistry(registry);
+        service2.setInterface(DemoService.class);
+        service2.setRef(new DemoServiceImpl());
+        service2.setMethods(Collections.singletonList(method));
+        service2.setProxy("testproxyfactory");
+
+        delayService.setProvider(provider);
+        delayService.setApplication(app);
+        delayService.setRegistry(registry);
+        delayService.setInterface(DemoService.class);
+        delayService.setRef(new DemoServiceImpl());
+        delayService.setMethods(Collections.singletonList(method));
+        delayService.setDelay(100);
+
+//        ApplicationModel.getConfigManager().clear();
+    }
+
+    @AfterEach
+    public void tearDown() {
+//        ApplicationModel.getConfigManager().clear();
+    }
+
+    @Test
+    public void testExport() throws Exception {
+        service.export();
+
+        assertThat(service.getExportedUrls(), hasSize(1));
+        URL url = service.toUrl();
+        assertThat(url.getProtocol(), equalTo("mockprotocol2"));
+        assertThat(url.getPath(), equalTo(DemoService.class.getName()));
+        assertThat(url.getParameters(), hasEntry(ANYHOST_KEY, "true"));
+        assertThat(url.getParameters(), hasEntry(APPLICATION_KEY, "app"));
+        assertThat(url.getParameters(), hasKey(BIND_IP_KEY));
+        assertThat(url.getParameters(), hasKey(BIND_PORT_KEY));
+        assertThat(url.getParameters(), hasEntry(EXPORT_KEY, "true"));
+        assertThat(url.getParameters(), hasEntry("echo.0.callback", "false"));
+        assertThat(url.getParameters(), hasEntry(GENERIC_KEY, "false"));
+        assertThat(url.getParameters(), hasEntry(INTERFACE_KEY, DemoService.class.getName()));
+        assertThat(url.getParameters(), hasKey(METHODS_KEY));
+        assertThat(url.getParameters().get(METHODS_KEY), containsString("echo"));
+        assertThat(url.getParameters(), hasEntry(SIDE_KEY, PROVIDER));
+        Mockito.verify(protocolDelegate).export(Mockito.any(Invoker.class));
+    }
+
+    @Test
+    public void testProxy() throws Exception {
+        service2.export();
+
+        assertThat(service2.getExportedUrls(), hasSize(1));
+        assertEquals(2, TestProxyFactory.count); // local injvm and registry protocol, so expected is 2
+    }
+
+
+    @Test
+    public void testDelayExport() throws Exception {
+        delayService.export();
+        assertTrue(delayService.getExportedUrls().isEmpty());
+        //add 300ms to ensure that the delayService has been exported
+        TimeUnit.MILLISECONDS.sleep(delayService.getDelay() + 300);
+        assertThat(delayService.getExportedUrls(), hasSize(1));
+    }
+
+    @Test
+    @Disabled("cannot pass in travis")
+    public void testUnexport() throws Exception {
+        System.setProperty(SHUTDOWN_WAIT_KEY, "0");
+        try {
+            service.export();
+            service.unexport();
+            Thread.sleep(1000);
+            Mockito.verify(exporter, Mockito.atLeastOnce()).unexport();
+        } finally {
+            System.clearProperty(SHUTDOWN_TIMEOUT_KEY);
+        }
+    }
+
+    @Test
+    public void testInterfaceClass() throws Exception {
+        ServiceConfig<Greeting> service = new ServiceConfig<Greeting>();
+        service.setInterface(Greeting.class.getName());
+        service.setRef(Mockito.mock(Greeting.class));
+        assertThat(service.getInterfaceClass() == Greeting.class, is(true));
+        service = new ServiceConfig<Greeting>();
+        service.setRef(Mockito.mock(Greeting.class, withSettings().extraInterfaces(GenericService.class)));
+        assertThat(service.getInterfaceClass() == GenericService.class, is(true));
+    }
+
+    @Test
+    public void testInterface1() throws Exception {
+        Assertions.assertThrows(IllegalStateException.class, () -> {
+            ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();
+            service.setInterface(DemoServiceImpl.class);
+        });
+    }
+
+    @Test
+    public void testInterface2() throws Exception {
+        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();
+        service.setInterface(DemoService.class);
+        assertThat(service.getInterface(), equalTo(DemoService.class.getName()));
+    }
+
+    @Test
+    public void testProvider() throws Exception {
+        ServiceConfig service = new ServiceConfig();
+        ProviderConfig provider = new ProviderConfig();
+        service.setProvider(provider);
+        assertThat(service.getProvider(), is(provider));
+    }
+
+    @Test
+    public void testGeneric1() throws Exception {
+        ServiceConfig service = new ServiceConfig();
+        service.setGeneric(GENERIC_SERIALIZATION_DEFAULT);
+        assertThat(service.getGeneric(), equalTo(GENERIC_SERIALIZATION_DEFAULT));
+        service.setGeneric(GENERIC_SERIALIZATION_NATIVE_JAVA);
+        assertThat(service.getGeneric(), equalTo(GENERIC_SERIALIZATION_NATIVE_JAVA));
+        service.setGeneric(GENERIC_SERIALIZATION_BEAN);
+        assertThat(service.getGeneric(), equalTo(GENERIC_SERIALIZATION_BEAN));
+    }
+
+    @Test
+    public void testGeneric2() throws Exception {
+        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+            ServiceConfig service = new ServiceConfig();
+            service.setGeneric("illegal");
+        });
+    }
+
+//    @Test
+//    public void testMock() throws Exception {
+//        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+//            ServiceConfig service = new ServiceConfig();
+//            service.setMock("true");
+//        });
+//    }
+//
+//    @Test
+//    public void testMock2() throws Exception {
+//        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+//            ServiceConfig service = new ServiceConfig();
+//            service.setMock(true);
+//        });
+//    }
+
+    @Test
+    public void testApplicationInUrl() {
+        service.export();
+        Assertions.assertNotNull(service.toUrl().getParameter(APPLICATION_KEY));
+        Assertions.assertEquals("app", service.toUrl().getParameter(APPLICATION_KEY));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/api/Box.java b/dubbo-test/src/test/java/org/apache/dubbo/config/api/Box.java
new file mode 100644
index 0000000..e63f924
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/api/Box.java
@@ -0,0 +1,23 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.api;
+
+public interface Box {
+
+    String getName();
+
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/api/DemoException.java b/dubbo-test/src/test/java/org/apache/dubbo/config/api/DemoException.java
new file mode 100644
index 0000000..2f32c3f
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/api/DemoException.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.api;
+
+/**
+ * DemoException
+ */
+public class DemoException extends Exception {
+
+    private static final long serialVersionUID = -8213943026163641747L;
+
+    public DemoException() {
+        super();
+    }
+
+    public DemoException(String message, Throwable cause) {
+        super(message, cause);
+    }
+
+    public DemoException(String message) {
+        super(message);
+    }
+
+    public DemoException(Throwable cause) {
+        super(cause);
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-test/src/test/java/org/apache/dubbo/config/api/DemoService.java
new file mode 100644
index 0000000..c5bc722
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/api/DemoService.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.api;
+
+import java.util.List;
+
+
+/**
+ * DemoService
+ */
+public interface DemoService {
+
+    String sayName(String name);
+
+    Box getBox();
+
+    void throwDemoException() throws DemoException;
+
+    List<User> getUsers(List<User> users);
+
+    int echo(int i);
+
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/api/Greeting.java b/dubbo-test/src/test/java/org/apache/dubbo/config/api/Greeting.java
new file mode 100644
index 0000000..c2afa98
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/api/Greeting.java
@@ -0,0 +1,24 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.api;
+
+import org.apache.dubbo.common.extension.SPI;
+
+@SPI
+public interface Greeting {
+    String hello();
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/api/User.java b/dubbo-test/src/test/java/org/apache/dubbo/config/api/User.java
new file mode 100644
index 0000000..5e55cbb
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/api/User.java
@@ -0,0 +1,65 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.api;
+
+import java.io.Serializable;
+
+/**
+ * User
+ */
+public class User implements Serializable {
+
+    private static final long serialVersionUID = 1L;
+
+    private String name;
+
+    public User() {
+    }
+
+    public User(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public int hashCode() {
+        return name == null ? -1 : name.hashCode();
+    }
+
+    @Override
+    public boolean equals(Object obj) {
+        if (!(obj instanceof User)) {
+            return false;
+        }
+        User other = (User) obj;
+        if (this == other) {
+            return true;
+        }
+        if (name != null && other.name != null) {
+            return name.equals(other.name);
+        }
+        return false;
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceConsumerBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..824de82
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceConsumerBootstrap.java
@@ -0,0 +1,52 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class ConsulDubboServiceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+                .application("consul-dubbo-consumer", app -> app.metadata(DEFAULT_METADATA_STORAGE_TYPE))
+                .registry("zookeeper", builder -> builder.address("consul://127.0.0.1:8500?registry-type=service&subscribed-services=consul-dubbo-provider")
+                        .useAsConfigCenter(true)
+                        .useAsMetadataCenter(true))
+                .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo"))
+                .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest"))
+                .start();
+
+        EchoService echoService = bootstrap.getCache().get(EchoService.class);
+        UserService userService = bootstrap.getCache().get(UserService.class);
+
+        for (int i = 0; i < 5; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+            System.out.println(userService.getUser(i * 1L));
+        }
+
+        bootstrap.stop();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceProviderBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..ef38944
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ConsulDubboServiceProviderBootstrap.java
@@ -0,0 +1,42 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl;
+
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;
+
+/**
+ * TODO
+ */
+public class ConsulDubboServiceProviderBootstrap {
+
+    public static void main(String[] args) {
+        DubboBootstrap.getInstance()
+                .application("consul-dubbo-provider", app -> app.metadata(DEFAULT_METADATA_STORAGE_TYPE))
+                .registry(builder -> builder.address("consul://127.0.0.1:8500?registry-type=service")
+                        .useAsConfigCenter(true)
+                        .useAsMetadataCenter(true))
+                .protocol("dubbo", builder -> builder.port(-1).name("dubbo"))
+                .protocol("rest", builder -> builder.port(8081).name("rest"))
+                .service("echo", builder -> builder.interfaceClass(EchoService.class).ref(new EchoServiceImpl()).protocolIds("dubbo"))
+                .service("user", builder -> builder.interfaceClass(UserService.class).ref(new UserServiceImpl()).protocolIds("rest"))
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
new file mode 100644
index 0000000..6136dd4
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboBootstrapTest.java
@@ -0,0 +1,154 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.constants.CommonConstants;
+import org.apache.dubbo.common.utils.ConfigUtils;
+import org.apache.dubbo.config.AbstractInterfaceConfigTest;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.utils.ConfigValidationUtils;
+import org.apache.dubbo.monitor.MonitorService;
+import org.apache.dubbo.registry.RegistryService;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.junit.jupiter.api.io.TempDir;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.nio.file.Path;
+import java.util.List;
+import java.util.Properties;
+
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.SHUTDOWN_WAIT_SECONDS_KEY;
+
+/**
+ * {@link DubboBootstrap} Test
+ *
+ * @since 2.7.5
+ */
+public class DubboBootstrapTest {
+
+    private static File dubboProperties;
+
+    @BeforeAll
+    public static void setUp(@TempDir Path folder) {
+        dubboProperties = folder.resolve(CommonConstants.DUBBO_PROPERTIES_KEY).toFile();
+        System.setProperty(CommonConstants.DUBBO_PROPERTIES_KEY, dubboProperties.getAbsolutePath());
+    }
+
+    @AfterEach
+    public void tearDown() throws IOException {
+
+    }
+
+    @Test
+    public void checkApplication() {
+        System.setProperty("dubbo.application.name", "demo");
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        applicationConfig.refresh();
+        Assertions.assertEquals("demo", applicationConfig.getName());
+        System.clearProperty("dubbo.application.name");
+    }
+
+    @Test
+    public void compatibleApplicationShutdown() {
+        try {
+            ConfigUtils.setProperties(null);
+            System.clearProperty(SHUTDOWN_WAIT_KEY);
+            System.clearProperty(SHUTDOWN_WAIT_SECONDS_KEY);
+
+            writeDubboProperties(SHUTDOWN_WAIT_KEY, "100");
+            ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig("demo"));
+            Assertions.assertEquals("100", System.getProperty(SHUTDOWN_WAIT_KEY));
+
+            System.clearProperty(SHUTDOWN_WAIT_KEY);
+            ConfigUtils.setProperties(null);
+            writeDubboProperties(SHUTDOWN_WAIT_SECONDS_KEY, "1000");
+            ConfigValidationUtils.validateApplicationConfig(new ApplicationConfig("demo"));
+            Assertions.assertEquals("1000", System.getProperty(SHUTDOWN_WAIT_SECONDS_KEY));
+        } finally {
+            ConfigUtils.setProperties(null);
+            System.clearProperty("dubbo.application.name");
+            System.clearProperty(SHUTDOWN_WAIT_KEY);
+            System.clearProperty(SHUTDOWN_WAIT_SECONDS_KEY);
+        }
+    }
+
+    @Test
+    public void testLoadRegistries() {
+        System.setProperty("dubbo.registry.address", "addr1");
+        AbstractInterfaceConfigTest.InterfaceConfig interfaceConfig = new AbstractInterfaceConfigTest.InterfaceConfig();
+        // FIXME: now we need to check first, then load
+        interfaceConfig.setApplication(new ApplicationConfig("testLoadRegistries"));
+        interfaceConfig.checkRegistry();
+        List<URL> urls = ConfigValidationUtils.loadRegistries(interfaceConfig, true);
+        Assertions.assertEquals(1, urls.size());
+        URL url = urls.get(0);
+        Assertions.assertEquals("registry", url.getProtocol());
+        Assertions.assertEquals("addr1:9090", url.getAddress());
+        Assertions.assertEquals(RegistryService.class.getName(), url.getPath());
+        Assertions.assertTrue(url.getParameters().containsKey("timestamp"));
+        Assertions.assertTrue(url.getParameters().containsKey("pid"));
+        Assertions.assertTrue(url.getParameters().containsKey("registry"));
+        Assertions.assertTrue(url.getParameters().containsKey("dubbo"));
+    }
+
+
+    @Test
+    public void testLoadMonitor() {
+        System.setProperty("dubbo.monitor.address", "monitor-addr:12080");
+        System.setProperty("dubbo.monitor.protocol", "monitor");
+        AbstractInterfaceConfigTest.InterfaceConfig interfaceConfig = new AbstractInterfaceConfigTest.InterfaceConfig();
+        interfaceConfig.setApplication(new ApplicationConfig("testLoadMonitor"));
+        interfaceConfig.setMonitor(new MonitorConfig());
+        URL url = ConfigValidationUtils.loadMonitor(interfaceConfig, new URL("dubbo", "addr1", 9090));
+        Assertions.assertEquals("monitor-addr:12080", url.getAddress());
+        Assertions.assertEquals(MonitorService.class.getName(), url.getParameter("interface"));
+        Assertions.assertNotNull(url.getParameter("dubbo"));
+        Assertions.assertNotNull(url.getParameter("pid"));
+        Assertions.assertNotNull(url.getParameter("timestamp"));
+    }
+
+    private void writeDubboProperties(String key, String value) {
+        OutputStream os = null;
+        try {
+            os = new BufferedOutputStream(new FileOutputStream(dubboProperties));
+            Properties properties = new Properties();
+            properties.put(key, value);
+            properties.store(os, "");
+            os.close();
+        } catch (IOException e) {
+            if (os != null) {
+                try {
+                    os.close();
+                } catch (IOException ioe) {
+                    // ignore
+                }
+            }
+        }
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceConsumerBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..f493c16
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceConsumerBootstrap.java
@@ -0,0 +1,58 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class DubboServiceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+                .application("dubbo-consumer-demo")
+                .protocol(builder -> builder.port(20887).name("dubbo"))
+                // Eureka
+//                .registry(builder -> builder.address("eureka://127.0.0.1:8761?registry-type=service&subscribed-services=dubbo-provider-demo"))
+
+                // Zookeeper
+                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service&subscribed-services=dubbo-provider-demo"))
+                .metadataReport(new MetadataReportConfig("zookeeper://127.0.0.1:2181"))
+
+                // Nacos
+                // .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry.type=service&subscribed.services=dubbo-provider-demo"))
+
+                // Consul
+                // .registry("consul", builder -> builder.address("consul://127.0.0.1:8500?registry.type=service&subscribed.services=dubbo-provider-demo").group("namespace1"))
+                .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo"))
+                .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest"))
+                .start();
+
+        EchoService echoService = bootstrap.getCache().get(EchoService.class);
+
+        for (int i = 0; i < 500; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+        }
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceProviderBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..35285dd
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceProviderBootstrap.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl;
+
+import java.util.Arrays;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class DubboServiceProviderBootstrap {
+
+    public static void main(String[] args) {
+        multipleRegistries();
+    }
+
+    private static void multipleRegistries() {
+        ProtocolConfig restProtocol = new ProtocolConfig();
+        restProtocol.setName("rest");
+        restProtocol.setId("rest");
+        restProtocol.setPort(-1);
+
+        RegistryConfig interfaceRegistry = new RegistryConfig();
+        interfaceRegistry.setId("interfaceRegistry");
+        interfaceRegistry.setAddress("zookeeper://127.0.0.1:2181");
+
+        RegistryConfig serviceRegistry = new RegistryConfig();
+        serviceRegistry.setId("serviceRegistry");
+        serviceRegistry.setAddress("zookeeper://127.0.0.1:2181?registry-type=service");
+
+        ServiceConfig<EchoService> echoService = new ServiceConfig<>();
+        echoService.setInterface(EchoService.class.getName());
+        echoService.setRef(new EchoServiceImpl());
+//        echoService.setRegistries(Arrays.asList(interfaceRegistry, serviceRegistry));
+
+        ServiceConfig<UserService> userService = new ServiceConfig<>();
+        userService.setInterface(UserService.class.getName());
+        userService.setRef(new UserServiceImpl());
+        userService.setProtocol(restProtocol);
+//        userService.setRegistries(Arrays.asList(interfaceRegistry, serviceRegistry));
+
+        ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-provider-demo");
+        applicationConfig.setMetadataType("remote");
+        DubboBootstrap.getInstance()
+                .application(applicationConfig)
+                // Zookeeper in service registry type
+//                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry.type=service"))
+                // Nacos
+//                .registry("zookeeper", builder -> builder.address("nacos://127.0.0.1:8848?registry.type=service"))
+                .registries(Arrays.asList(interfaceRegistry, serviceRegistry))
+//                .registry(RegistryBuilder.newBuilder().address("consul://127.0.0.1:8500?registry.type=service").build())
+                .protocol(builder -> builder.port(-1).name("dubbo"))
+                .metadataReport(new MetadataReportConfig("zookeeper://127.0.0.1:2181"))
+                .service(echoService)
+                .service(userService)
+                .start()
+                .await();
+    }
+
+    private static void testSCCallDubbo() {
+
+    }
+
+    private static void testDubboCallSC() {
+
+    }
+
+    private static void testDubboTansormation() {
+
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceProviderMinimumBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceProviderMinimumBootstrap.java
new file mode 100644
index 0000000..b4e3cfa
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/DubboServiceProviderMinimumBootstrap.java
@@ -0,0 +1,38 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl;
+
+/**
+ * TODO
+ */
+public class DubboServiceProviderMinimumBootstrap {
+
+    public static void main(String[] args) {
+        DubboBootstrap.getInstance()
+                .application("dubbo-provider-demo")
+                .registry(builder -> builder.address("zookeeper://127.0.0.1:2181?registry-type=service"))
+//                .registry(builder -> builder.address("eureka://127.0.0.1:8761?registry-type=service"))
+                .protocol(builder -> builder.port(-1).name("dubbo"))
+                .service("echo", builder -> builder.interfaceClass(EchoService.class).ref(new EchoServiceImpl()))
+                .service("user", builder -> builder.interfaceClass(UserService.class).ref(new UserServiceImpl()))
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EchoService.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EchoService.java
new file mode 100644
index 0000000..7969c07
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EchoService.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+/**
+ * Echo Service
+ *
+ * @since 2.7.5
+ */
+public interface EchoService {
+
+    String GROUP = "DEFAULT";
+
+    String VERSION = "1.0.0";
+
+    String echo(String message);
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EchoServiceImpl.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EchoServiceImpl.java
new file mode 100644
index 0000000..7c9225d
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EchoServiceImpl.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.rpc.RpcContext;
+
+import static java.lang.String.format;
+
+/**
+ * The implementation of {@link EchoService}
+ *
+ * @see EchoService
+ * @since 2.7.5
+ */
+public class EchoServiceImpl implements EchoService {
+
+    @Override
+    public String echo(String message) {
+        RpcContext rpcContext = RpcContext.getContext();
+        return format("[%s:%s] ECHO - %s", rpcContext.getLocalHost(), rpcContext.getLocalPort(), message);
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EtcdDubboServiceConsumerBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EtcdDubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..8d61524
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EtcdDubboServiceConsumerBootstrap.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class EtcdDubboServiceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+                .application("dubbo-consumer-demo")
+                // Zookeeper
+                .protocol(builder -> builder.port(20887).name("dubbo"))
+                .registry("etcd3", builder -> builder.address("etcd3://127.0.0.1:2379?registry-type=service&subscribed-services=dubbo-provider-demo"))
+                .metadataReport(new MetadataReportConfig("etcd://127.0.0.1:2379"))
+                // Nacos
+//                .registry("consul", builder -> builder.address("consul://127.0.0.1:8500?registry.type=service&subscribed.services=dubbo-provider-demo").group("namespace1"))
+                .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo"))
+                .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest"))
+                .start();
+
+        EchoService echoService = bootstrap.getCache().get(EchoService.class);
+
+        for (int i = 0; i < 500; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+        }
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EtcdDubboServiceProviderBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EtcdDubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..cbe7b01
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/EtcdDubboServiceProviderBootstrap.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl;
+
+import java.util.Arrays;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class EtcdDubboServiceProviderBootstrap {
+
+    public static void main(String[] args) {
+        multipleRegistries();
+    }
+
+    private static void multipleRegistries() {
+        ProtocolConfig restProtocol = new ProtocolConfig();
+        restProtocol.setName("rest");
+        restProtocol.setId("rest");
+        restProtocol.setPort(-1);
+
+        RegistryConfig interfaceRegistry = new RegistryConfig();
+        interfaceRegistry.setId("interfaceRegistry");
+        interfaceRegistry.setAddress("etcd3://127.0.0.1:2379");
+
+        RegistryConfig serviceRegistry = new RegistryConfig();
+        serviceRegistry.setId("serviceRegistry");
+        serviceRegistry.setAddress("etcd3://127.0.0.1:2379?registry-type=service");
+
+        ServiceConfig<EchoService> echoService = new ServiceConfig<>();
+        echoService.setInterface(EchoService.class.getName());
+        echoService.setRef(new EchoServiceImpl());
+//        echoService.setRegistries(Arrays.asList(interfaceRegistry, serviceRegistry));
+
+        ServiceConfig<UserService> userService = new ServiceConfig<>();
+        userService.setInterface(UserService.class.getName());
+        userService.setRef(new UserServiceImpl());
+        userService.setProtocol(restProtocol);
+//        userService.setRegistries(Arrays.asList(interfaceRegistry, serviceRegistry));
+
+        ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-provider-demo");
+//        applicationConfig.setMetadataType("remote");
+        DubboBootstrap.getInstance()
+                .application(applicationConfig)
+                // Zookeeper in service registry type
+//                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181?registry.type=service"))
+                // Nacos
+//                .registry("zookeeper", builder -> builder.address("nacos://127.0.0.1:8848?registry.type=service"))
+                .registries(Arrays.asList(interfaceRegistry, serviceRegistry))
+//                .registry(RegistryBuilder.newBuilder().address("consul://127.0.0.1:8500?registry.type=service").build())
+                .protocol(builder -> builder.port(-1).name("dubbo"))
+//                .metadataReport(new MetadataReportConfig("etcd://127.0.0.1:2379"))
+                .service(echoService)
+                .service(userService)
+                .start()
+                .await();
+    }
+
+    private static void testSCCallDubbo() {
+
+    }
+
+    private static void testDubboCallSC() {
+
+    }
+
+    private static void testDubboTansormation() {
+
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..37262e2
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceConsumerBootstrap.java
@@ -0,0 +1,56 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+
+import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class NacosDubboServiceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+
+        ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-nacos-consumer-demo");
+        applicationConfig.setMetadataType(REMOTE_METADATA_STORAGE_TYPE);
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+                .application(applicationConfig)
+                // Nacos in service registry type
+                .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?registry-type=service")
+                        .useAsConfigCenter(true)
+                        .useAsMetadataCenter(true))
+                // Nacos in traditional registry type
+//                .registry("nacos-traditional", builder -> builder.address("nacos://127.0.0.1:8848"))
+                .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo"))
+                .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest"))
+                .start();
+
+        EchoService echoService = bootstrap.getCache().get(EchoService.class);
+        UserService userService = bootstrap.getCache().get(UserService.class);
+
+        for (int i = 0; i < 5; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+            System.out.println(userService.getUser(i * 1L));
+        }
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..72c597a
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/NacosDubboServiceProviderBootstrap.java
@@ -0,0 +1,51 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl;
+
+import static org.apache.dubbo.common.constants.CommonConstants.REMOTE_METADATA_STORAGE_TYPE;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class NacosDubboServiceProviderBootstrap {
+
+    public static void main(String[] args) {
+        ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-nacos-provider-demo");
+        applicationConfig.setMetadataType(REMOTE_METADATA_STORAGE_TYPE);
+        DubboBootstrap.getInstance()
+                .application(applicationConfig)
+                // Nacos in service registry type
+                .registry("nacos", builder -> builder.address("nacos://127.0.0.1:8848?username=nacos&password=nacos")
+                        .parameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE))
+                // Nacos in traditional registry type
+//                .registry("nacos-traditional", builder -> builder.address("nacos://127.0.0.1:8848"))
+                .protocol("dubbo", builder -> builder.port(20885).name("dubbo"))
+                .protocol("rest", builder -> builder.port(9090).name("rest"))
+                .service(builder -> builder.id("echo").interfaceClass(EchoService.class).ref(new EchoServiceImpl()).protocolIds("dubbo"))
+                .service(builder -> builder.id("user").interfaceClass(UserService.class).ref(new UserServiceImpl()).protocolIds("rest"))
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java
new file mode 100644
index 0000000..27f3eb9
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceConsumerBootstrap.java
@@ -0,0 +1,55 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+
+import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class ZookeeperDubboServiceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+                .application("zookeeper-dubbo-consumer", app -> app.metadata(COMPOSITE_METADATA_STORAGE_TYPE))
+                .registry("zookeeper", builder -> builder.address("zookeeper://127.0.0.1:2181")
+                        .parameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE)
+                        .useAsConfigCenter(true)
+                        .useAsMetadataCenter(true))
+                .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo").services("zookeeper-dubbo-provider"))
+                .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest"))
+                .start();
+
+        EchoService echoService = bootstrap.getCache().get(EchoService.class);
+        UserService userService = bootstrap.getCache().get(UserService.class);
+
+        for (int i = 0; i < 5; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+            System.out.println(userService.getUser(i * 1L));
+        }
+
+        bootstrap.stop();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java
new file mode 100644
index 0000000..889aae2
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/ZookeeperDubboServiceProviderBootstrap.java
@@ -0,0 +1,43 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap;
+
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+import org.apache.dubbo.config.bootstrap.rest.UserServiceImpl;
+
+import static org.apache.dubbo.common.constants.CommonConstants.COMPOSITE_METADATA_STORAGE_TYPE;
+import static org.apache.dubbo.common.constants.RegistryConstants.REGISTRY_TYPE_KEY;
+import static org.apache.dubbo.common.constants.RegistryConstants.SERVICE_REGISTRY_TYPE;
+
+/**
+ * TODO
+ */
+public class ZookeeperDubboServiceProviderBootstrap {
+
+    public static void main(String[] args) {
+        DubboBootstrap.getInstance()
+                .application("zookeeper-dubbo-provider", app -> app.metadata(COMPOSITE_METADATA_STORAGE_TYPE))
+                .registry(builder -> builder.address("127.0.0.1:2181").protocol("zookeeper")
+                        .parameter(REGISTRY_TYPE_KEY, SERVICE_REGISTRY_TYPE))
+                .protocol("dubbo", builder -> builder.port(-1).name("dubbo"))
+                .protocol("rest", builder -> builder.port(8081).name("rest"))
+                .service("echo", builder -> builder.interfaceClass(EchoService.class).ref(new EchoServiceImpl()).protocolIds("dubbo"))
+                .service("user", builder -> builder.interfaceClass(UserService.class).ref(new UserServiceImpl()).protocolIds("rest"))
+                .start()
+                .await();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractBuilderTest.java
new file mode 100644
index 0000000..d32b5cd
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractBuilderTest.java
@@ -0,0 +1,126 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.AbstractConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class AbstractBuilderTest {
+
+    @Test
+    void id() {
+        Builder builder = new Builder();
+        builder.id("id");
+        Assertions.assertEquals("id", builder.build().getId());
+    }
+
+    @Test
+    void prefix() {
+        Builder builder = new Builder();
+        builder.prefix("prefix");
+        Assertions.assertEquals("prefix", builder.build().getPrefix());
+    }
+
+    @Test
+    void appendParameter() {
+        Map<String, String> source = null;
+
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("default.num", "one");
+        parameters.put("num", "ONE");
+        source = AbstractBuilder.appendParameters(source, parameters);
+
+        Assertions.assertTrue(source.containsKey("default.num"));
+        Assertions.assertEquals("ONE", source.get("num"));
+    }
+
+    @Test
+    void appendParameter2() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one1");
+        source.put("num", "ONE1");
+
+        Map<String, String> parameters = new HashMap<>();
+        parameters.put("default.num", "one");
+        parameters.put("num", "ONE");
+        source = AbstractBuilder.appendParameters(source, parameters);
+
+        Assertions.assertTrue(source.containsKey("default.num"));
+        Assertions.assertEquals("ONE", source.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = null;
+
+        source = AbstractBuilder.appendParameter(source, "default.num", "one");
+        source = AbstractBuilder.appendParameter(source, "num", "ONE");
+
+        Assertions.assertTrue(source.containsKey("default.num"));
+        Assertions.assertEquals("ONE", source.get("num"));
+    }
+
+    @Test
+    void appendParameters2() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one1");
+        source.put("num", "ONE1");
+
+        source = AbstractBuilder.appendParameter(source, "default.num", "one");
+        source = AbstractBuilder.appendParameter(source, "num", "ONE");
+
+        Assertions.assertTrue(source.containsKey("default.num"));
+        Assertions.assertEquals("ONE", source.get("num"));
+    }
+
+    @Test
+    void build() {
+        Builder builder = new Builder();
+        builder.id("id");
+        builder.prefix("prefix");
+
+        Config config = builder.build();
+        Config config2 = builder.build();
+
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+
+        Assertions.assertNotSame(config, config2);
+    }
+
+    private static class Builder extends AbstractBuilder<Config, Builder> {
+        public Config build() {
+            Config parameterConfig = new Config();
+            super.build(parameterConfig);
+
+            return parameterConfig;
+        }
+
+        @Override
+        protected Builder getThis() {
+            return this;
+        }
+    }
+
+    private static class Config extends AbstractConfig {
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractInterfaceBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractInterfaceBuilderTest.java
new file mode 100644
index 0000000..c3bb9cf
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractInterfaceBuilderTest.java
@@ -0,0 +1,311 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.AbstractInterfaceConfig;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConfigCenterConfig;
+import org.apache.dubbo.config.MetadataReportConfig;
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.RegistryConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+class AbstractInterfaceBuilderTest {
+
+    @Test
+    void local() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.local("GreetingMock");
+        Assertions.assertEquals("GreetingMock", builder.build().getLocal());
+    }
+
+    @Test
+    void local1() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.local((Boolean) null);
+        Assertions.assertNull(builder.build().getLocal());
+        builder.local(false);
+        Assertions.assertEquals("false", builder.build().getLocal());
+        builder.local(true);
+        Assertions.assertEquals("true", builder.build().getLocal());
+    }
+
+    @Test
+    void stub() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.stub("GreetingMock");
+        Assertions.assertEquals("GreetingMock", builder.build().getStub());
+    }
+
+    @Test
+    void stub1() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.stub((Boolean) null);
+        Assertions.assertNull(builder.build().getLocal());
+        builder.stub(false);
+        Assertions.assertEquals("false", builder.build().getStub());
+        builder.stub(true);
+        Assertions.assertEquals("true", builder.build().getStub());
+    }
+
+    @Test
+    void monitor() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.monitor("123");
+
+        MonitorConfig monitorConfig = new MonitorConfig("123");
+        Assertions.assertEquals(monitorConfig, builder.build().getMonitor());
+    }
+
+    @Test
+    void monitor1() {
+        MonitorConfig monitorConfig = new MonitorConfig("123");
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.monitor(monitorConfig);
+
+        Assertions.assertEquals(monitorConfig, builder.build().getMonitor());
+    }
+
+    @Test
+    void proxy() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.proxy("mockproxyfactory");
+
+        Assertions.assertEquals("mockproxyfactory", builder.build().getProxy());
+    }
+
+    @Test
+    void cluster() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.cluster("mockcluster");
+
+        Assertions.assertEquals("mockcluster", builder.build().getCluster());
+    }
+
+    @Test
+    void filter() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.filter("mockfilter");
+
+        Assertions.assertEquals("mockfilter", builder.build().getFilter());
+    }
+
+    @Test
+    void listener() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.listener("mockinvokerlistener");
+
+        Assertions.assertEquals("mockinvokerlistener", builder.build().getListener());
+    }
+
+    @Test
+    void owner() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.owner("owner");
+
+        Assertions.assertEquals("owner", builder.build().getOwner());
+    }
+
+    @Test
+    void connections() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.connections(1);
+
+        Assertions.assertEquals(1, builder.build().getConnections().intValue());
+    }
+
+    @Test
+    void layer() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.layer("layer");
+
+        Assertions.assertEquals("layer", builder.build().getLayer());
+    }
+
+    @Test
+    void application() {
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.application(applicationConfig);
+
+        Assertions.assertEquals(applicationConfig, builder.build().getApplication());
+    }
+
+    @Test
+    void module() {
+        ModuleConfig moduleConfig = new ModuleConfig();
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.module(moduleConfig);
+
+        Assertions.assertEquals(moduleConfig, builder.build().getModule());
+    }
+
+    @Test
+    void addRegistries() {
+        RegistryConfig registryConfig = new RegistryConfig();
+
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.addRegistries(Collections.singletonList(registryConfig));
+
+        Assertions.assertEquals(1, builder.build().getRegistries().size());
+        Assertions.assertSame(registryConfig, builder.build().getRegistries().get(0));
+        Assertions.assertSame(registryConfig, builder.build().getRegistry());
+    }
+
+    @Test
+    void addRegistry() {
+        RegistryConfig registryConfig = new RegistryConfig();
+
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.addRegistry(registryConfig);
+
+        Assertions.assertEquals(1, builder.build().getRegistries().size());
+        Assertions.assertSame(registryConfig, builder.build().getRegistries().get(0));
+        Assertions.assertSame(registryConfig, builder.build().getRegistry());
+    }
+
+    @Test
+    void registryIds() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.registryIds("registryIds");
+
+        Assertions.assertEquals("registryIds", builder.build().getRegistryIds());
+    }
+
+    @Test
+    void onconnect() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.onconnect("onconnect");
+
+        Assertions.assertEquals("onconnect", builder.build().getOnconnect());
+    }
+
+    @Test
+    void ondisconnect() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.ondisconnect("ondisconnect");
+
+        Assertions.assertEquals("ondisconnect", builder.build().getOndisconnect());
+    }
+
+    @Test
+    void metadataReportConfig() {
+        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
+
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.metadataReportConfig(metadataReportConfig);
+
+        Assertions.assertEquals(metadataReportConfig, builder.build().getMetadataReportConfig());
+    }
+
+    @Test
+    void configCenter() {
+        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
+
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.configCenter(configCenterConfig);
+
+        Assertions.assertEquals(configCenterConfig, builder.build().getConfigCenter());
+    }
+
+    @Test
+    void callbacks() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.callbacks(2);
+        Assertions.assertEquals(2, builder.build().getCallbacks().intValue());
+    }
+
+    @Test
+    void scope() {
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.scope("scope");
+
+        Assertions.assertEquals("scope", builder.build().getScope());
+    }
+
+    @Test
+    void build() {
+        MonitorConfig monitorConfig = new MonitorConfig("123");
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        ModuleConfig moduleConfig = new ModuleConfig();
+        RegistryConfig registryConfig = new RegistryConfig();
+        MetadataReportConfig metadataReportConfig = new MetadataReportConfig();
+        ConfigCenterConfig configCenterConfig = new ConfigCenterConfig();
+
+        InterfaceBuilder builder = new InterfaceBuilder();
+        builder.id("id").prefix("prefix").local(true).stub(false).monitor("123").proxy("mockproxyfactory").cluster("mockcluster")
+                .filter("mockfilter").listener("mockinvokerlistener").owner("owner").connections(1)
+                .layer("layer").application(applicationConfig).module(moduleConfig)
+                .addRegistry(registryConfig).registryIds("registryIds")
+                .onconnect("onconnet").ondisconnect("ondisconnect")
+                .metadataReportConfig(metadataReportConfig)
+                .configCenter(configCenterConfig)
+                .callbacks(2).scope("scope");
+
+        InterfaceConfig config = builder.build();
+        InterfaceConfig config2 = builder.build();
+
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertEquals("true", config.getLocal());
+        Assertions.assertEquals("false", config.getStub());
+        Assertions.assertEquals(monitorConfig, config.getMonitor());
+        Assertions.assertEquals("mockproxyfactory", config.getProxy());
+        Assertions.assertEquals("mockcluster", config.getCluster());
+        Assertions.assertEquals("mockfilter", config.getFilter());
+        Assertions.assertEquals("mockinvokerlistener", config.getListener());
+        Assertions.assertEquals("owner", config.getOwner());
+        Assertions.assertEquals(1, config.getConnections().intValue());
+        Assertions.assertEquals("layer", config.getLayer());
+        Assertions.assertEquals(applicationConfig, config.getApplication());
+        Assertions.assertEquals(moduleConfig, config.getModule());
+        Assertions.assertEquals(registryConfig, config.getRegistry());
+        Assertions.assertEquals("registryIds", config.getRegistryIds());
+        Assertions.assertEquals("onconnet", config.getOnconnect());
+        Assertions.assertEquals("ondisconnect", config.getOndisconnect());
+        Assertions.assertEquals(metadataReportConfig, config.getMetadataReportConfig());
+        Assertions.assertEquals(configCenterConfig, config.getConfigCenter());
+        Assertions.assertEquals(2, config.getCallbacks().intValue());
+        Assertions.assertEquals("scope", config.getScope());
+
+        Assertions.assertNotSame(config, config2);
+    }
+
+    private static class InterfaceBuilder extends AbstractInterfaceBuilder<InterfaceConfig, InterfaceBuilder> {
+
+        public InterfaceConfig build() {
+            InterfaceConfig config = new InterfaceConfig();
+            super.build(config);
+
+            return config;
+        }
+
+        @Override
+        protected InterfaceBuilder getThis() {
+            return this;
+        }
+    }
+
+    private static class InterfaceConfig extends AbstractInterfaceConfig {
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractMethodBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractMethodBuilderTest.java
new file mode 100644
index 0000000..13a179f
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractMethodBuilderTest.java
@@ -0,0 +1,196 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.AbstractMethodConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class AbstractMethodBuilderTest {
+
+    @Test
+    void timeout() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.timeout(10);
+
+        Assertions.assertEquals(10, builder.build().getTimeout());
+    }
+
+    @Test
+    void retries() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.retries(3);
+
+        Assertions.assertEquals(3, builder.build().getRetries());
+    }
+
+    @Test
+    void actives() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.actives(3);
+
+        Assertions.assertEquals(3, builder.build().getActives());
+    }
+
+    @Test
+    void loadbalance() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.loadbalance("mockloadbalance");
+
+        Assertions.assertEquals("mockloadbalance", builder.build().getLoadbalance());
+    }
+
+    @Test
+    void async() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.async(true);
+
+        Assertions.assertTrue(builder.build().isAsync());
+    }
+
+    @Test
+    void sent() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.sent(true);
+
+        Assertions.assertTrue(builder.build().getSent());
+    }
+
+    @Test
+    void mock() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.mock("mock");
+        Assertions.assertEquals("mock", builder.build().getMock());
+        builder.mock("return null");
+        Assertions.assertEquals("return null", builder.build().getMock());
+    }
+
+    @Test
+    void mock1() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.mock(true);
+        Assertions.assertEquals("true", builder.build().getMock());
+        builder.mock(false);
+        Assertions.assertEquals("false", builder.build().getMock());
+    }
+
+    @Test
+    void merger() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.merger("merger");
+        Assertions.assertEquals("merger", builder.build().getMerger());
+    }
+
+    @Test
+    void cache() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.cache("cache");
+        Assertions.assertEquals("cache", builder.build().getCache());
+    }
+
+    @Test
+    void validation() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.validation("validation");
+        Assertions.assertEquals("validation", builder.build().getValidation());
+    }
+
+    @Test
+    void appendParameter() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        MethodBuilder builder = new MethodBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void forks() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.forks(5);
+
+        Assertions.assertEquals(5, builder.build().getForks());
+    }
+
+    @Test
+    void build() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.id("id").prefix("prefix").timeout(1).retries(2).actives(3).loadbalance("mockloadbalance").async(true)
+                .sent(false).mock("mock").merger("merger").cache("cache").validation("validation")
+                .appendParameter("default.num", "one");
+
+        MethodConfig config = builder.build();
+        MethodConfig config2 = builder.build();
+
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertEquals(1, config.getTimeout());
+        Assertions.assertEquals(2, config.getRetries());
+        Assertions.assertEquals(3, config.getActives());
+        Assertions.assertEquals("mockloadbalance", config.getLoadbalance());
+        Assertions.assertTrue(config.isAsync());
+        Assertions.assertFalse(config.getSent());
+        Assertions.assertEquals("mock", config.getMock());
+        Assertions.assertEquals("merger", config.getMerger());
+        Assertions.assertEquals("cache", config.getCache());
+        Assertions.assertEquals("validation", config.getValidation());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+
+        Assertions.assertNotSame(config, config2);
+
+    }
+
+    private static class MethodBuilder extends AbstractMethodBuilder<MethodConfig, MethodBuilder> {
+
+        public MethodConfig build() {
+            MethodConfig parameterConfig = new MethodConfig();
+            super.build(parameterConfig);
+
+            return parameterConfig;
+        }
+
+        @Override
+        protected MethodBuilder getThis() {
+            return this;
+        }
+    }
+
+    private static class MethodConfig extends AbstractMethodConfig {
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractReferenceBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractReferenceBuilderTest.java
new file mode 100644
index 0000000..c505ca9
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractReferenceBuilderTest.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.AbstractReferenceConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;
+
+class AbstractReferenceBuilderTest {
+
+    @Test
+    void check() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.check(true);
+        Assertions.assertTrue(builder.build().isCheck());
+        builder.check(false);
+        Assertions.assertFalse(builder.build().isCheck());
+    }
+
+    @Test
+    void init() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.init(true);
+        Assertions.assertTrue(builder.build().isInit());
+        builder.init(false);
+        Assertions.assertFalse(builder.build().isInit());
+    }
+
+    @Test
+    void generic() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.generic(true);
+        Assertions.assertTrue(builder.build().isGeneric());
+        builder.generic(false);
+        Assertions.assertFalse(builder.build().isGeneric());
+    }
+
+    @Test
+    void generic1() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.generic(GENERIC_SERIALIZATION_BEAN);
+        Assertions.assertEquals(GENERIC_SERIALIZATION_BEAN, builder.build().getGeneric());
+    }
+
+    @Test
+    void injvm() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.injvm(true);
+        Assertions.assertTrue(builder.build().isInjvm());
+        builder.injvm(false);
+        Assertions.assertFalse(builder.build().isInjvm());
+    }
+
+    @Test
+    void lazy() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.lazy(true);
+        Assertions.assertTrue(builder.build().getLazy());
+        builder.lazy(false);
+        Assertions.assertFalse(builder.build().getLazy());
+    }
+
+    @Test
+    void reconnect() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.reconnect("reconnect");
+        Assertions.assertEquals("reconnect", builder.build().getReconnect());
+    }
+
+    @Test
+    void sticky() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.sticky(true);
+        Assertions.assertTrue(builder.build().getSticky());
+        builder.sticky(false);
+        Assertions.assertFalse(builder.build().getSticky());
+    }
+
+    @Test
+    void version() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.version("version");
+        Assertions.assertEquals("version", builder.build().getVersion());
+    }
+
+    @Test
+    void group() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.group("group");
+        Assertions.assertEquals("group", builder.build().getGroup());
+    }
+
+    @Test
+    void build() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.check(true).init(false).generic(true).injvm(false).lazy(true).reconnect("reconnect").sticky(false)
+                .version("version").group("group").id("id").prefix("prefix");
+
+        ReferenceConfig config = builder.build();
+        ReferenceConfig config2 = builder.build();
+
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertTrue(config.isCheck());
+        Assertions.assertFalse(config.isInit());
+        Assertions.assertTrue(config.isGeneric());
+        Assertions.assertFalse(config.isInjvm());
+        Assertions.assertTrue(config.getLazy());
+        Assertions.assertFalse(config.getSticky());
+        Assertions.assertEquals("reconnect", config.getReconnect());
+        Assertions.assertEquals("version", config.getVersion());
+        Assertions.assertEquals("group", config.getGroup());
+
+        Assertions.assertNotSame(config, config2);
+    }
+
+    private static class ReferenceBuilder extends AbstractReferenceBuilder<ReferenceConfig, ReferenceBuilder> {
+
+        public ReferenceConfig build() {
+            ReferenceConfig parameterConfig = new ReferenceConfig();
+            super.build(parameterConfig);
+
+            return parameterConfig;
+        }
+
+        @Override
+        protected ReferenceBuilder getThis() {
+            return this;
+        }
+    }
+
+    private static class ReferenceConfig extends AbstractReferenceConfig {
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractServiceBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractServiceBuilderTest.java
new file mode 100644
index 0000000..d030160
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/AbstractServiceBuilderTest.java
@@ -0,0 +1,245 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.AbstractServiceConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+class AbstractServiceBuilderTest {
+
+    @Test
+    void version() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.version("version");
+        Assertions.assertEquals("version", builder.build().getVersion());
+    }
+
+    @Test
+    void group() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.group("group");
+        Assertions.assertEquals("group", builder.build().getGroup());
+    }
+
+    @Test
+    void deprecated() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.deprecated(true);
+        Assertions.assertTrue(builder.build().isDeprecated());
+        builder.deprecated(false);
+        Assertions.assertFalse(builder.build().isDeprecated());
+    }
+
+    @Test
+    void delay() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.delay(1000);
+        Assertions.assertEquals(1000, builder.build().getDelay());
+    }
+
+    @Test
+    void export() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.export(true);
+        Assertions.assertTrue(builder.build().getExport());
+        builder.export(false);
+        Assertions.assertFalse(builder.build().getExport());
+    }
+
+    @Test
+    void weight() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.weight(500);
+        Assertions.assertEquals(500, builder.build().getWeight());
+    }
+
+    @Test
+    void document() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.document("http://dubbo.apache.org");
+        Assertions.assertEquals("http://dubbo.apache.org", builder.build().getDocument());
+    }
+
+    @Test
+    void dynamic() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.dynamic(true);
+        Assertions.assertTrue(builder.build().isDynamic());
+        builder.dynamic(false);
+        Assertions.assertFalse(builder.build().isDynamic());
+    }
+
+    @Test
+    void token() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.token("token");
+        Assertions.assertEquals("token", builder.build().getToken());
+    }
+
+    @Test
+    void token1() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.token(true);
+        Assertions.assertEquals("true", builder.build().getToken());
+        builder.token(false);
+        Assertions.assertEquals("false", builder.build().getToken());
+        builder.token((Boolean) null);
+        Assertions.assertNull(builder.build().getToken());
+    }
+
+    @Test
+    void accesslog() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.accesslog("accesslog");
+        Assertions.assertEquals("accesslog", builder.build().getAccesslog());
+    }
+
+    @Test
+    void accesslog1() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.accesslog(true);
+        Assertions.assertEquals("true", builder.build().getAccesslog());
+        builder.accesslog(false);
+        Assertions.assertEquals("false", builder.build().getAccesslog());
+        builder.accesslog((Boolean) null);
+        Assertions.assertNull(builder.build().getAccesslog());
+    }
+
+    @Test
+    void addProtocols() {
+        ProtocolConfig protocol = new ProtocolConfig();
+        ServiceBuilder builder = new ServiceBuilder();
+        Assertions.assertNull(builder.build().getProtocols());
+        builder.addProtocols(Collections.singletonList(protocol));
+        Assertions.assertNotNull(builder.build().getProtocols());
+        Assertions.assertEquals(1, builder.build().getProtocols().size());
+    }
+
+    @Test
+    void addProtocol() {
+        ProtocolConfig protocol = new ProtocolConfig();
+        ServiceBuilder builder = new ServiceBuilder();
+        Assertions.assertNull(builder.build().getProtocols());
+        builder.addProtocol(protocol);
+        Assertions.assertNotNull(builder.build().getProtocols());
+        Assertions.assertEquals(1, builder.build().getProtocols().size());
+        Assertions.assertEquals(protocol, builder.build().getProtocol());
+    }
+
+    @Test
+    void protocolIds() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.protocolIds("protocolIds");
+        Assertions.assertEquals("protocolIds", builder.build().getProtocolIds());
+    }
+
+    @Test
+    void tag() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.tag("tag");
+        Assertions.assertEquals("tag", builder.build().getTag());
+    }
+
+    @Test
+    void executes() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.executes(10);
+        Assertions.assertEquals(10, builder.build().getExecutes());
+    }
+
+    @Test
+    void register() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.register(true);
+        Assertions.assertTrue(builder.build().isRegister());
+        builder.register(false);
+        Assertions.assertFalse(builder.build().isRegister());
+    }
+
+    @Test
+    void warmup() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.warmup(100);
+        Assertions.assertEquals(100, builder.build().getWarmup());
+    }
+
+    @Test
+    void serialization() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.serialization("serialization");
+        Assertions.assertEquals("serialization", builder.build().getSerialization());
+    }
+
+    @Test
+    void build() {
+        ProtocolConfig protocol = new ProtocolConfig();
+
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.version("version").group("group").deprecated(true).delay(1000).export(false).weight(1)
+                .document("document").dynamic(true).token("token").accesslog("accesslog")
+                .addProtocol(protocol).protocolIds("protocolIds").tag("tag").executes(100).register(false)
+                .warmup(200).serialization("serialization").id("id").prefix("prefix");
+
+        ServiceConfig config = builder.build();
+        ServiceConfig config2 = builder.build();
+
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertEquals("version", config.getVersion());
+        Assertions.assertEquals("group", config.getGroup());
+        Assertions.assertEquals("document", config.getDocument());
+        Assertions.assertEquals("token", config.getToken());
+        Assertions.assertEquals("accesslog", config.getAccesslog());
+        Assertions.assertEquals("protocolIds", config.getProtocolIds());
+        Assertions.assertEquals("tag", config.getTag());
+        Assertions.assertEquals("serialization", config.getSerialization());
+        Assertions.assertTrue(config.isDeprecated());
+        Assertions.assertFalse(config.getExport());
+        Assertions.assertTrue(config.isDynamic());
+        Assertions.assertFalse(config.isRegister());
+        Assertions.assertEquals(1000, config.getDelay());
+        Assertions.assertEquals(1, config.getWeight());
+        Assertions.assertEquals(100, config.getExecutes());
+        Assertions.assertEquals(200, config.getWarmup());
+
+        Assertions.assertNotSame(config, config2);
+    }
+
+    private static class ServiceBuilder extends AbstractServiceBuilder<ServiceConfig, ServiceBuilder> {
+
+        public ServiceConfig build() {
+            ServiceConfig parameterConfig = new ServiceConfig();
+            super.build(parameterConfig);
+
+            return parameterConfig;
+        }
+
+        @Override
+        protected ServiceBuilder getThis() {
+            return this;
+        }
+    }
+
+    private static class ServiceConfig extends AbstractServiceConfig {
+
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ApplicationBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ApplicationBuilderTest.java
new file mode 100644
index 0000000..6c37eae
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ApplicationBuilderTest.java
@@ -0,0 +1,255 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.RegistryConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+class ApplicationBuilderTest {
+
+    @Test
+    void name() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.name("app");
+        Assertions.assertEquals("app", builder.build().getName());
+    }
+
+    @Test
+    void version() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.version("version");
+        Assertions.assertEquals("version", builder.build().getVersion());
+    }
+
+    @Test
+    void owner() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.owner("owner");
+        Assertions.assertEquals("owner", builder.build().getOwner());
+    }
+
+    @Test
+    void organization() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.organization("organization");
+        Assertions.assertEquals("organization", builder.build().getOrganization());
+    }
+
+    @Test
+    void architecture() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.architecture("architecture");
+        Assertions.assertEquals("architecture", builder.build().getArchitecture());
+    }
+
+    @Test
+    void environment() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        Assertions.assertEquals("product", builder.build().getEnvironment());
+        builder.environment("develop");
+        Assertions.assertEquals("develop", builder.build().getEnvironment());
+        builder.environment("test");
+        Assertions.assertEquals("test", builder.build().getEnvironment());
+        builder.environment("product");
+        Assertions.assertEquals("product", builder.build().getEnvironment());
+    }
+
+    @Test
+    void compiler() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.compiler("compiler");
+        Assertions.assertEquals("compiler", builder.build().getCompiler());
+    }
+
+    @Test
+    void logger() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.logger("log4j");
+        Assertions.assertEquals("log4j", builder.build().getLogger());
+    }
+
+    @Test
+    void addRegistry() {
+        RegistryConfig registry = new RegistryConfig();
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.addRegistry(registry);
+        Assertions.assertNotNull(builder.build().getRegistry());
+        Assertions.assertEquals(1, builder.build().getRegistries().size());
+        Assertions.assertSame(registry, builder.build().getRegistry());
+    }
+
+    @Test
+    void addRegistries() {
+        RegistryConfig registry = new RegistryConfig();
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.addRegistries(Collections.singletonList(registry));
+        Assertions.assertNotNull(builder.build().getRegistry());
+        Assertions.assertEquals(1, builder.build().getRegistries().size());
+        Assertions.assertSame(registry, builder.build().getRegistry());
+    }
+
+    @Test
+    void registryIds() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.registryIds("registryIds");
+        Assertions.assertEquals("registryIds", builder.build().getRegistryIds());
+    }
+
+    @Test
+    void monitor() {
+        MonitorConfig monitor = new MonitorConfig("monitor-addr");
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.monitor(monitor);
+        Assertions.assertSame(monitor, builder.build().getMonitor());
+        Assertions.assertEquals("monitor-addr", builder.build().getMonitor().getAddress());
+    }
+
+    @Test
+    void monitor1() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.monitor("monitor-addr");
+        Assertions.assertEquals("monitor-addr", builder.build().getMonitor().getAddress());
+    }
+
+    @Test
+    void isDefault() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.isDefault(true);
+        Assertions.assertTrue(builder.build().isDefault());
+        builder.isDefault(false);
+        Assertions.assertFalse(builder.build().isDefault());
+        builder.isDefault(null);
+        Assertions.assertNull(builder.build().isDefault());
+    }
+
+    @Test
+    void dumpDirectory() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.dumpDirectory("dumpDirectory");
+        Assertions.assertEquals("dumpDirectory", builder.build().getDumpDirectory());
+    }
+
+    @Test
+    void qosEnable() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.qosEnable(true);
+        Assertions.assertTrue(builder.build().getQosEnable());
+        builder.qosEnable(false);
+        Assertions.assertFalse(builder.build().getQosEnable());
+        builder.qosEnable(null);
+        Assertions.assertNull(builder.build().getQosEnable());
+    }
+
+    @Test
+    void qosPort() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.qosPort(8080);
+        Assertions.assertEquals(8080, builder.build().getQosPort());
+    }
+
+    @Test
+    void qosAcceptForeignIp() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.qosAcceptForeignIp(true);
+        Assertions.assertTrue(builder.build().getQosAcceptForeignIp());
+        builder.qosAcceptForeignIp(false);
+        Assertions.assertFalse(builder.build().getQosAcceptForeignIp());
+        builder.qosAcceptForeignIp(null);
+        Assertions.assertNull(builder.build().getQosAcceptForeignIp());
+    }
+
+    @Test
+    void shutwait() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.shutwait("shutwait");
+        Assertions.assertEquals("shutwait", builder.build().getShutwait());
+    }
+
+    @Test
+    void appendParameter() {
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void build() {
+        MonitorConfig monitor = new MonitorConfig("monitor-addr");
+        RegistryConfig registry = new RegistryConfig();
+
+        ApplicationBuilder builder = new ApplicationBuilder();
+        builder.id("id").prefix("prefix").name("name").version("version").owner("owner").organization("organization").architecture("architecture")
+                .environment("develop").compiler("compiler").logger("log4j").monitor(monitor).isDefault(false)
+                .dumpDirectory("dumpDirectory").qosEnable(true).qosPort(8080).qosAcceptForeignIp(false)
+                .shutwait("shutwait").registryIds("registryIds").addRegistry(registry)
+                .appendParameter("default.num", "one");
+
+        ApplicationConfig config = builder.build();
+        ApplicationConfig config2 = builder.build();
+
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertEquals("name", config.getName());
+        Assertions.assertEquals("version", config.getVersion());
+        Assertions.assertEquals("owner", config.getOwner());
+        Assertions.assertEquals("organization", config.getOrganization());
+        Assertions.assertEquals("architecture", config.getArchitecture());
+        Assertions.assertEquals("develop", config.getEnvironment());
+        Assertions.assertEquals("compiler", config.getCompiler());
+        Assertions.assertEquals("log4j", config.getLogger());
+        Assertions.assertSame(monitor, config.getMonitor());
+        Assertions.assertFalse(config.isDefault());
+        Assertions.assertEquals("dumpDirectory", config.getDumpDirectory());
+        Assertions.assertTrue(config.getQosEnable());
+        Assertions.assertEquals(8080, config.getQosPort());
+        Assertions.assertFalse(config.getQosAcceptForeignIp());
+        Assertions.assertEquals("shutwait", config.getShutwait());
+        Assertions.assertEquals("registryIds", config.getRegistryIds());
+        Assertions.assertSame(registry, config.getRegistry());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ArgumentBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ArgumentBuilderTest.java
new file mode 100644
index 0000000..1b6638d
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ArgumentBuilderTest.java
@@ -0,0 +1,63 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ArgumentConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ArgumentBuilderTest {
+
+    @Test
+    void index() {
+        ArgumentBuilder builder = new ArgumentBuilder();
+        builder.index(1);
+        Assertions.assertEquals(1, builder.build().getIndex());
+    }
+
+    @Test
+    void type() {
+        ArgumentBuilder builder = new ArgumentBuilder();
+        builder.type("int");
+        Assertions.assertEquals("int", builder.build().getType());
+    }
+
+    @Test
+    void callback() {
+        ArgumentBuilder builder = new ArgumentBuilder();
+        builder.callback(true);
+        Assertions.assertTrue(builder.build().isCallback());
+        builder.callback(false);
+        Assertions.assertFalse(builder.build().isCallback());
+    }
+
+    @Test
+    void build() {
+        ArgumentBuilder builder = new ArgumentBuilder();
+        builder.index(1).type("int").callback(true);
+
+        ArgumentConfig argument1 = builder.build();
+        ArgumentConfig argument2 = builder.build();
+
+        Assertions.assertTrue(argument1.isCallback());
+        Assertions.assertEquals("int", argument1.getType());
+        Assertions.assertEquals(1, argument1.getIndex());
+
+        Assertions.assertNotSame(argument1, argument2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConfigCenterBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConfigCenterBuilderTest.java
new file mode 100644
index 0000000..b9f321b
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConfigCenterBuilderTest.java
@@ -0,0 +1,169 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ConfigCenterConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class ConfigCenterBuilderTest {
+
+    @Test
+    void protocol() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.protocol("protocol");
+        Assertions.assertEquals("protocol", builder.build().getProtocol());
+    }
+
+    @Test
+    void address() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.address("address");
+        Assertions.assertEquals("address", builder.build().getAddress());
+    }
+
+    @Test
+    void cluster() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.cluster("cluster");
+        Assertions.assertEquals("cluster", builder.build().getCluster());
+    }
+
+    @Test
+    void namespace() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.namespace("namespace");
+        Assertions.assertEquals("namespace", builder.build().getNamespace());
+    }
+
+    @Test
+    void group() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.group("group");
+        Assertions.assertEquals("group", builder.build().getGroup());
+    }
+
+    @Test
+    void username() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.username("username");
+        Assertions.assertEquals("username", builder.build().getUsername());
+    }
+
+    @Test
+    void password() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.password("password");
+        Assertions.assertEquals("password", builder.build().getPassword());
+    }
+
+    @Test
+    void timeout() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.timeout(1000L);
+        Assertions.assertEquals(1000L, builder.build().getTimeout());
+    }
+
+    @Test
+    void highestPriority() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.highestPriority(true);
+        Assertions.assertTrue(builder.build().isHighestPriority());
+    }
+
+    @Test
+    void check() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.check(true);
+        Assertions.assertTrue(builder.build().isCheck());
+    }
+
+    @Test
+    void configFile() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.configFile("configFile");
+        Assertions.assertEquals("configFile", builder.build().getConfigFile());
+    }
+
+    @Test
+    void appConfigFile() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.appConfigFile("appConfigFile");
+        Assertions.assertEquals("appConfigFile", builder.build().getAppConfigFile());
+    }
+
+    @Test
+    void appendParameter() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void build() {
+        ConfigCenterBuilder builder = new ConfigCenterBuilder();
+        builder.check(true).protocol("protocol").address("address").appConfigFile("appConfigFile")
+                .cluster("cluster").configFile("configFile").group("group").highestPriority(false)
+                .namespace("namespace").password("password").timeout(1000L).username("usernama")
+                .appendParameter("default.num", "one").id("id").prefix("prefix");
+
+        ConfigCenterConfig config = builder.build();
+        ConfigCenterConfig config2 = builder.build();
+
+        Assertions.assertTrue(config.isCheck());
+        Assertions.assertFalse(config.isHighestPriority());
+        Assertions.assertEquals(1000L, config.getTimeout());
+        Assertions.assertEquals("protocol", config.getProtocol());
+        Assertions.assertEquals("address", config.getAddress());
+        Assertions.assertEquals("appConfigFile", config.getAppConfigFile());
+        Assertions.assertEquals("cluster", config.getCluster());
+        Assertions.assertEquals("configFile", config.getConfigFile());
+        Assertions.assertEquals("group", config.getGroup());
+        Assertions.assertEquals("namespace", config.getNamespace());
+        Assertions.assertEquals("password", config.getPassword());
+        Assertions.assertEquals("usernama", config.getUsername());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConsumerBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConsumerBuilderTest.java
new file mode 100644
index 0000000..bb7e131
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ConsumerBuilderTest.java
@@ -0,0 +1,95 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ConsumerConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ConsumerBuilderTest {
+
+    @Test
+    void isDefault() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.isDefault(false);
+        Assertions.assertFalse(builder.build().isDefault());
+    }
+
+    @Test
+    void client() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.client("client");
+        Assertions.assertEquals("client", builder.build().getClient());
+    }
+
+    @Test
+    void threadPool() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.threadPool("threadPool");
+        Assertions.assertEquals("threadPool", builder.build().getThreadpool());
+    }
+
+    @Test
+    void coreThreads() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.coreThreads(10);
+        Assertions.assertEquals(10, builder.build().getCorethreads());
+    }
+
+    @Test
+    void threads() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.threads(100);
+        Assertions.assertEquals(100, builder.build().getThreads());
+    }
+
+    @Test
+    void queues() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.queues(200);
+        Assertions.assertEquals(200, builder.build().getQueues());
+    }
+
+    @Test
+    void shareConnections() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.shareConnections(300);
+        Assertions.assertEquals(300, builder.build().getShareconnections());
+    }
+
+    @Test
+    void build() {
+        ConsumerBuilder builder = new ConsumerBuilder();
+        builder.isDefault(true).client("client").threadPool("threadPool").coreThreads(10).threads(100).queues(200)
+                .shareConnections(300).id("id").prefix("prefix");
+
+        ConsumerConfig config = builder.build();
+        ConsumerConfig config2 = builder.build();
+
+        Assertions.assertTrue(config.isDefault());
+        Assertions.assertEquals("client", config.getClient());
+        Assertions.assertEquals("threadPool", config.getThreadpool());
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertEquals(10, config.getCorethreads());
+        Assertions.assertEquals(100, config.getThreads());
+        Assertions.assertEquals(200, config.getQueues());
+        Assertions.assertEquals(300, config.getShareconnections());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MetadataReportBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MetadataReportBuilderTest.java
new file mode 100644
index 0000000..5d60dd8
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MetadataReportBuilderTest.java
@@ -0,0 +1,151 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.MetadataReportConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class MetadataReportBuilderTest {
+
+    @Test
+    void address() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.address("address");
+        Assertions.assertEquals("address", builder.build().getAddress());
+    }
+
+    @Test
+    void username() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.username("username");
+        Assertions.assertEquals("username", builder.build().getUsername());
+    }
+
+    @Test
+    void password() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.password("password");
+        Assertions.assertEquals("password", builder.build().getPassword());
+    }
+
+    @Test
+    void timeout() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.timeout(1000);
+        Assertions.assertEquals(1000, builder.build().getTimeout());
+    }
+
+    @Test
+    void group() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.group("group");
+        Assertions.assertEquals("group", builder.build().getGroup());
+    }
+
+    @Test
+    void appendParameter() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void retryTimes() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.retryTimes(1);
+        Assertions.assertEquals(1, builder.build().getRetryTimes());
+    }
+
+    @Test
+    void retryPeriod() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.retryPeriod(2);
+        Assertions.assertEquals(2, builder.build().getRetryPeriod());
+    }
+
+    @Test
+    void cycleReport() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.cycleReport(true);
+        Assertions.assertTrue(builder.build().getCycleReport());
+        builder.cycleReport(false);
+        Assertions.assertFalse(builder.build().getCycleReport());
+        builder.cycleReport(null);
+        Assertions.assertNull(builder.build().getCycleReport());
+    }
+
+    @Test
+    void syncReport() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.syncReport(true);
+        Assertions.assertTrue(builder.build().getSyncReport());
+        builder.syncReport(false);
+        Assertions.assertFalse(builder.build().getSyncReport());
+        builder.syncReport(null);
+        Assertions.assertNull(builder.build().getSyncReport());
+    }
+
+    @Test
+    void build() {
+        MetadataReportBuilder builder = new MetadataReportBuilder();
+        builder.address("address").username("username").password("password").timeout(1000).group("group")
+                .retryTimes(1).retryPeriod(2).cycleReport(true).syncReport(false)
+                .appendParameter("default.num", "one").id("id").prefix("prefix");
+
+        MetadataReportConfig config = builder.build();
+        MetadataReportConfig config2 = builder.build();
+
+        Assertions.assertTrue(config.getCycleReport());
+        Assertions.assertFalse(config.getSyncReport());
+        Assertions.assertEquals(1000, config.getTimeout());
+        Assertions.assertEquals(1, config.getRetryTimes());
+        Assertions.assertEquals(2, config.getRetryPeriod());
+        Assertions.assertEquals("address", config.getAddress());
+        Assertions.assertEquals("username", config.getUsername());
+        Assertions.assertEquals("password", config.getPassword());
+        Assertions.assertEquals("group", config.getGroup());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MethodBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MethodBuilderTest.java
new file mode 100644
index 0000000..9196c48
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MethodBuilderTest.java
@@ -0,0 +1,189 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ArgumentConfig;
+import org.apache.dubbo.config.MethodConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+class MethodBuilderTest {
+
+    @Test
+    void name() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.name("name");
+        Assertions.assertEquals("name", builder.build().getName());
+    }
+
+    @Test
+    void stat() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.stat(1);
+        Assertions.assertEquals(1, builder.build().getStat());
+    }
+
+    @Test
+    void retry() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.retry(true);
+        Assertions.assertTrue(builder.build().isRetry());
+    }
+
+    @Test
+    void reliable() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.reliable(true);
+        Assertions.assertTrue(builder.build().isReliable());
+    }
+
+    @Test
+    void executes() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.executes(1);
+        Assertions.assertEquals(1, builder.build().getExecutes());
+    }
+
+    @Test
+    void deprecated() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.deprecated(true);
+        Assertions.assertTrue(builder.build().getDeprecated());
+    }
+
+    @Test
+    void sticky() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.sticky(true);
+        Assertions.assertTrue(builder.build().getSticky());
+    }
+
+    @Test
+    void isReturn() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.isReturn(true);
+        Assertions.assertTrue(builder.build().isReturn());
+    }
+
+    @Test
+    void oninvoke() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.oninvoke("on-invoke-object");
+        Assertions.assertEquals("on-invoke-object", builder.build().getOninvoke());
+    }
+
+    @Test
+    void oninvokeMethod() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.oninvokeMethod("on-invoke-method");
+        Assertions.assertEquals("on-invoke-method", builder.build().getOninvokeMethod());
+    }
+
+    @Test
+    void onreturn() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.onreturn("on-return-object");
+        Assertions.assertEquals("on-return-object", builder.build().getOnreturn());
+    }
+
+    @Test
+    void onreturnMethod() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.onreturnMethod("on-return-method");
+        Assertions.assertEquals("on-return-method", builder.build().getOnreturnMethod());
+    }
+
+    @Test
+    void onthrow() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.onthrow("on-throw-object");
+        Assertions.assertEquals("on-throw-object", builder.build().getOnthrow());
+    }
+
+    @Test
+    void onthrowMethod() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.onthrowMethod("on-throw-method");
+        Assertions.assertEquals("on-throw-method", builder.build().getOnthrowMethod());
+    }
+
+    @Test
+    void addArguments() {
+        ArgumentConfig argument = new ArgumentConfig();
+        MethodBuilder builder = new MethodBuilder();
+        builder.addArguments(Collections.singletonList(argument));
+        Assertions.assertTrue(builder.build().getArguments().contains(argument));
+        Assertions.assertEquals(1, builder.build().getArguments().size());
+    }
+
+    @Test
+    void addArgument() {
+        ArgumentConfig argument = new ArgumentConfig();
+        MethodBuilder builder = new MethodBuilder();
+        builder.addArgument(argument);
+        Assertions.assertTrue(builder.build().getArguments().contains(argument));
+        Assertions.assertEquals(1, builder.build().getArguments().size());
+    }
+
+    @Test
+    void service() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.service("service");
+        Assertions.assertEquals("service", builder.build().getService());
+    }
+
+    @Test
+    void serviceId() {
+        MethodBuilder builder = new MethodBuilder();
+        builder.serviceId("serviceId");
+        Assertions.assertEquals("serviceId", builder.build().getServiceId());
+    }
+
+    @Test
+    void build() {
+        ArgumentConfig argument = new ArgumentConfig();
+        MethodBuilder builder = new MethodBuilder();
+        builder.name("name").stat(1).retry(true).reliable(false).executes(2).deprecated(true).sticky(false)
+                .isReturn(true).oninvoke("on-invoke-object").oninvokeMethod("on-invoke-method").service("service")
+                .onreturn("on-return-object").onreturnMethod("on-return-method").serviceId("serviceId")
+                .onthrow("on-throw-object").onthrowMethod("on-throw-method").addArgument(argument);
+
+        MethodConfig config = builder.build();
+        MethodConfig config2 = builder.build();
+
+        Assertions.assertTrue(config.isRetry());
+        Assertions.assertFalse(config.isReliable());
+        Assertions.assertTrue(config.getDeprecated());
+        Assertions.assertFalse(config.getSticky());
+        Assertions.assertTrue(config.isReturn());
+        Assertions.assertEquals(1, config.getStat());
+        Assertions.assertEquals(2, config.getExecutes());
+        Assertions.assertEquals("on-invoke-object", config.getOninvoke());
+        Assertions.assertEquals("on-invoke-method", config.getOninvokeMethod());
+        Assertions.assertEquals("on-return-object", config.getOnreturn());
+        Assertions.assertEquals("on-return-method", config.getOnreturnMethod());
+        Assertions.assertEquals("on-throw-object", config.getOnthrow());
+        Assertions.assertEquals("on-throw-method", config.getOnthrowMethod());
+        Assertions.assertEquals("name", config.getName());
+        Assertions.assertEquals("service", config.getService());
+        Assertions.assertEquals("serviceId", config.getServiceId());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ModuleBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ModuleBuilderTest.java
new file mode 100644
index 0000000..bbf7d2e
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ModuleBuilderTest.java
@@ -0,0 +1,112 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ModuleConfig;
+import org.apache.dubbo.config.MonitorConfig;
+import org.apache.dubbo.config.RegistryConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+class ModuleBuilderTest {
+
+    @Test
+    void name() {
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.name("name");
+        Assertions.assertEquals("name", builder.build().getName());
+    }
+
+    @Test
+    void version() {
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.version("version");
+        Assertions.assertEquals("version", builder.build().getVersion());
+    }
+
+    @Test
+    void owner() {
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.owner("owner");
+        Assertions.assertEquals("owner", builder.build().getOwner());
+    }
+
+    @Test
+    void organization() {
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.organization("organization");
+        Assertions.assertEquals("organization", builder.build().getOrganization());
+    }
+
+    @Test
+    void addRegistries() {
+        RegistryConfig registry = new RegistryConfig();
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.addRegistries(Collections.singletonList(registry));
+        Assertions.assertTrue(builder.build().getRegistries().contains(registry));
+        Assertions.assertEquals(1, builder.build().getRegistries().size());
+    }
+
+    @Test
+    void addRegistry() {
+        RegistryConfig registry = new RegistryConfig();
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.addRegistry(registry);
+        Assertions.assertTrue(builder.build().getRegistries().contains(registry));
+        Assertions.assertEquals(1, builder.build().getRegistries().size());
+    }
+
+    @Test
+    void monitor() {
+        MonitorConfig monitor = new MonitorConfig();
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.monitor(monitor);
+        Assertions.assertSame(monitor, builder.build().getMonitor());
+    }
+
+    @Test
+    void isDefault() {
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.isDefault(true);
+        Assertions.assertTrue(builder.build().isDefault());
+    }
+
+    @Test
+    void build() {
+        RegistryConfig registry = new RegistryConfig();
+        MonitorConfig monitor = new MonitorConfig();
+
+        ModuleBuilder builder = new ModuleBuilder();
+        builder.name("name").version("version").owner("owner").organization("organization").addRegistry(registry)
+                .monitor(monitor).isDefault(false);
+
+        ModuleConfig config = builder.build();
+        ModuleConfig config2 = builder.build();
+
+        Assertions.assertEquals("name", config.getName());
+        Assertions.assertEquals("version", config.getVersion());
+        Assertions.assertEquals("owner", config.getOwner());
+        Assertions.assertEquals("organization", config.getOrganization());
+        Assertions.assertTrue(builder.build().getRegistries().contains(registry));
+        Assertions.assertSame(monitor, builder.build().getMonitor());
+        Assertions.assertFalse(config.isDefault());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MonitorBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MonitorBuilderTest.java
new file mode 100644
index 0000000..ca4005f
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/MonitorBuilderTest.java
@@ -0,0 +1,135 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.MonitorConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class MonitorBuilderTest {
+
+    @Test
+    void protocol() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.protocol("protocol");
+        Assertions.assertEquals("protocol", builder.build().getProtocol());
+    }
+
+    @Test
+    void address() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.address("address");
+        Assertions.assertEquals("address", builder.build().getAddress());
+    }
+
+    @Test
+    void username() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.username("username");
+        Assertions.assertEquals("username", builder.build().getUsername());
+    }
+
+    @Test
+    void password() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.password("password");
+        Assertions.assertEquals("password", builder.build().getPassword());
+    }
+
+    @Test
+    void group() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.group("group");
+        Assertions.assertEquals("group", builder.build().getGroup());
+    }
+
+    @Test
+    void version() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.version("version");
+        Assertions.assertEquals("version", builder.build().getVersion());
+    }
+
+    @Test
+    void interval() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.interval("interval");
+        Assertions.assertEquals("interval", builder.build().getInterval());
+    }
+
+    @Test
+    void isDefault() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.isDefault(true);
+        Assertions.assertTrue(builder.build().isDefault());
+    }
+
+    @Test
+    void appendParameter() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void build() {
+        MonitorBuilder builder = new MonitorBuilder();
+        builder.protocol("protocol").address("address").group("group").interval("interval").isDefault(true)
+                .password("password").username("username").version("version")
+                .appendParameter("default.num", "one").id("id").prefix("prefix");
+
+        MonitorConfig config = builder.build();
+        MonitorConfig config2 = builder.build();
+
+        Assertions.assertEquals("protocol", config.getProtocol());
+        Assertions.assertEquals("address", config.getAddress());
+        Assertions.assertEquals("group", config.getGroup());
+        Assertions.assertEquals("interval", config.getInterval());
+        Assertions.assertEquals("password", config.getPassword());
+        Assertions.assertEquals("username", config.getUsername());
+        Assertions.assertEquals("version", config.getVersion());
+        Assertions.assertTrue(config.isDefault());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProtocolBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProtocolBuilderTest.java
new file mode 100644
index 0000000..8a0711e
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProtocolBuilderTest.java
@@ -0,0 +1,338 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ProtocolConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class ProtocolBuilderTest {
+
+    @Test
+    void name() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.name("name");
+        Assertions.assertEquals("name", builder.build().getName());
+    }
+
+    @Test
+    void host() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.host("host");
+        Assertions.assertEquals("host", builder.build().getHost());
+    }
+
+    @Test
+    void port() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.port(8080);
+        Assertions.assertEquals(8080, builder.build().getPort());
+    }
+
+    @Test
+    void contextpath() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.contextpath("contextpath");
+        Assertions.assertEquals("contextpath", builder.build().getContextpath());
+    }
+
+    @Test
+    void path() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.path("path");
+        Assertions.assertEquals("path", builder.build().getPath());
+    }
+
+    @Test
+    void threadpool() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.threadpool("mockthreadpool");
+        Assertions.assertEquals("mockthreadpool", builder.build().getThreadpool());
+    }
+
+    @Test
+    void corethreads() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.corethreads(10);
+        Assertions.assertEquals(10, builder.build().getCorethreads());
+    }
+
+    @Test
+    void threads() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.threads(20);
+        Assertions.assertEquals(20, builder.build().getThreads());
+    }
+
+    @Test
+    void iothreads() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.iothreads(25);
+        Assertions.assertEquals(25, builder.build().getIothreads());
+    }
+
+    @Test
+    void queues() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.queues(30);
+        Assertions.assertEquals(30, builder.build().getQueues());
+    }
+
+    @Test
+    void accepts() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.accepts(35);
+        Assertions.assertEquals(35, builder.build().getAccepts());
+    }
+
+    @Test
+    void codec() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.codec("mockcodec");
+        Assertions.assertEquals("mockcodec", builder.build().getCodec());
+    }
+
+    @Test
+    void serialization() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.serialization("serialization");
+        Assertions.assertEquals("serialization", builder.build().getSerialization());
+    }
+
+    @Test
+    void charset() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.charset("utf-8");
+        Assertions.assertEquals("utf-8", builder.build().getCharset());
+    }
+
+    @Test
+    void payload() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.payload(40);
+        Assertions.assertEquals(40, builder.build().getPayload());
+    }
+
+    @Test
+    void buffer() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.buffer(1024);
+        Assertions.assertEquals(1024, builder.build().getBuffer());
+    }
+
+    @Test
+    void heartbeat() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.heartbeat(1000);
+        Assertions.assertEquals(1000, builder.build().getHeartbeat());
+    }
+
+    @Test
+    void accesslog() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.accesslog("accesslog");
+        Assertions.assertEquals("accesslog", builder.build().getAccesslog());
+    }
+
+    @Test
+    void transporter() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.transporter("mocktransporter");
+        Assertions.assertEquals("mocktransporter", builder.build().getTransporter());
+    }
+
+    @Test
+    void exchanger() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.exchanger("mockexchanger");
+        Assertions.assertEquals("mockexchanger", builder.build().getExchanger());
+    }
+
+    @Test
+    void dispatcher() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.dispatcher("mockdispatcher");
+        Assertions.assertEquals("mockdispatcher", builder.build().getDispatcher());
+    }
+
+    @Test
+    void dispather() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.dispather("mockdispatcher");
+        Assertions.assertEquals("mockdispatcher", builder.build().getDispather());
+    }
+
+    @Test
+    void networker() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.networker("networker");
+        Assertions.assertEquals("networker", builder.build().getNetworker());
+    }
+
+    @Test
+    void server() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.server("server");
+        Assertions.assertEquals("server", builder.build().getServer());
+    }
+
+    @Test
+    void client() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.client("client");
+        Assertions.assertEquals("client", builder.build().getClient());
+    }
+
+    @Test
+    void telnet() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.telnet("mocktelnethandler");
+        Assertions.assertEquals("mocktelnethandler", builder.build().getTelnet());
+    }
+
+    @Test
+    void prompt() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.prompt("prompt");
+        Assertions.assertEquals("prompt", builder.build().getPrompt());
+    }
+
+    @Test
+    void status() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.status("mockstatuschecker");
+        Assertions.assertEquals("mockstatuschecker", builder.build().getStatus());
+    }
+
+    @Test
+    void register() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.register(true);
+        Assertions.assertTrue(builder.build().isRegister());
+    }
+
+    @Test
+    void keepAlive() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.keepAlive(true);
+        Assertions.assertTrue(builder.build().getKeepAlive());
+    }
+
+    @Test
+    void optimizer() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.optimizer("optimizer");
+        Assertions.assertEquals("optimizer", builder.build().getOptimizer());
+    }
+
+    @Test
+    void extension() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.extension("extension");
+        Assertions.assertEquals("extension", builder.build().getExtension());
+    }
+
+    @Test
+    void appendParameter() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void isDefault() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.isDefault(true);
+        Assertions.assertTrue(builder.build().isDefault());
+    }
+
+    @Test
+    void build() {
+        ProtocolBuilder builder = new ProtocolBuilder();
+        builder.name("name").host("host").port(8080).contextpath("contextpath").threadpool("mockthreadpool")
+                .corethreads(1).threads(2).iothreads(3).queues(4).accepts(5).codec("mockcodec")
+                .serialization("serialization").charset("utf-8").payload(6).buffer(1024).heartbeat(1000)
+                .accesslog("accesslog").transporter("mocktransporter").exchanger("mockexchanger")
+                .dispatcher("mockdispatcher").networker("networker").server("server").client("client")
+                .telnet("mocktelnethandler").prompt("prompt").status("mockstatuschecker").register(true).keepAlive(false)
+                .optimizer("optimizer").extension("extension").isDefault(true)
+                .appendParameter("default.num", "one").id("id").prefix("prefix");
+
+        ProtocolConfig config = builder.build();
+        ProtocolConfig config2 = builder.build();
+
+        Assertions.assertEquals(8080, config.getPort());
+        Assertions.assertEquals(1, config.getCorethreads());
+        Assertions.assertEquals(2, config.getThreads());
+        Assertions.assertEquals(3, config.getIothreads());
+        Assertions.assertEquals(4, config.getQueues());
+        Assertions.assertEquals(5, config.getAccepts());
+        Assertions.assertEquals(6, config.getPayload());
+        Assertions.assertEquals(1024, config.getBuffer());
+        Assertions.assertEquals(1000, config.getHeartbeat());
+        Assertions.assertEquals("name", config.getName());
+        Assertions.assertEquals("host", config.getHost());
+        Assertions.assertEquals("contextpath", config.getContextpath());
+        Assertions.assertEquals("mockthreadpool", config.getThreadpool());
+        Assertions.assertEquals("mockcodec", config.getCodec());
+        Assertions.assertEquals("serialization", config.getSerialization());
+        Assertions.assertEquals("utf-8", config.getCharset());
+        Assertions.assertEquals("accesslog", config.getAccesslog());
+        Assertions.assertEquals("mocktransporter", config.getTransporter());
+        Assertions.assertEquals("mockexchanger", config.getExchanger());
+        Assertions.assertEquals("mockdispatcher", config.getDispatcher());
+        Assertions.assertEquals("networker", config.getNetworker());
+        Assertions.assertEquals("server", config.getServer());
+        Assertions.assertEquals("client", config.getClient());
+        Assertions.assertEquals("mocktelnethandler", config.getTelnet());
+        Assertions.assertEquals("prompt", config.getPrompt());
+        Assertions.assertEquals("mockstatuschecker", config.getStatus());
+        Assertions.assertEquals("optimizer", config.getOptimizer());
+        Assertions.assertEquals("extension", config.getExtension());
+        Assertions.assertTrue(config.isRegister());
+        Assertions.assertFalse(config.getKeepAlive());
+        Assertions.assertTrue(config.isDefault());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProviderBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProviderBuilderTest.java
new file mode 100644
index 0000000..5f10b6c
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ProviderBuilderTest.java
@@ -0,0 +1,227 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ProviderConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+class ProviderBuilderTest {
+
+    @Test
+    void setHost() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.host("host");
+        Assertions.assertEquals("host", builder.build().getHost());
+    }
+
+    @Test
+    void port() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.port(8080);
+        Assertions.assertEquals(8080, builder.build().getPort());
+    }
+
+    @Test
+    void contextPath() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.contextPath("contextpath");
+        Assertions.assertEquals("contextpath", builder.build().getContextpath());
+    }
+
+    @Test
+    void threadPool() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.threadPool("mockthreadpool");
+        Assertions.assertEquals("mockthreadpool", builder.build().getThreadpool());
+    }
+
+    @Test
+    void threads() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.threads(20);
+        Assertions.assertEquals(20, builder.build().getThreads());
+    }
+
+    @Test
+    void ioThreads() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.ioThreads(25);
+        Assertions.assertEquals(25, builder.build().getIothreads());
+    }
+
+    @Test
+    void queues() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.queues(30);
+        Assertions.assertEquals(30, builder.build().getQueues());
+    }
+
+    @Test
+    void accepts() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.accepts(35);
+        Assertions.assertEquals(35, builder.build().getAccepts());
+    }
+
+    @Test
+    void codec() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.codec("mockcodec");
+        Assertions.assertEquals("mockcodec", builder.build().getCodec());
+    }
+
+    @Test
+    void charset() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.charset("utf-8");
+        Assertions.assertEquals("utf-8", builder.build().getCharset());
+    }
+
+    @Test
+    void payload() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.payload(40);
+        Assertions.assertEquals(40, builder.build().getPayload());
+    }
+
+    @Test
+    void buffer() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.buffer(1024);
+        Assertions.assertEquals(1024, builder.build().getBuffer());
+    }
+
+    @Test
+    void transporter() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.transporter("mocktransporter");
+        Assertions.assertEquals("mocktransporter", builder.build().getTransporter());
+    }
+
+    @Test
+    void exchanger() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.exchanger("mockexchanger");
+        Assertions.assertEquals("mockexchanger", builder.build().getExchanger());
+    }
+
+    @Test
+    void dispatcher() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.dispatcher("mockdispatcher");
+        Assertions.assertEquals("mockdispatcher", builder.build().getDispatcher());
+    }
+
+    @Test
+    void networker() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.networker("networker");
+        Assertions.assertEquals("networker", builder.build().getNetworker());
+    }
+
+    @Test
+    void server() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.server("server");
+        Assertions.assertEquals("server", builder.build().getServer());
+    }
+
+    @Test
+    void client() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.client("client");
+        Assertions.assertEquals("client", builder.build().getClient());
+    }
+
+    @Test
+    void telnet() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.telnet("mocktelnethandler");
+        Assertions.assertEquals("mocktelnethandler", builder.build().getTelnet());
+    }
+
+    @Test
+    void prompt() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.prompt("prompt");
+        Assertions.assertEquals("prompt", builder.build().getPrompt());
+    }
+
+    @Test
+    void status() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.status("mockstatuschecker");
+        Assertions.assertEquals("mockstatuschecker", builder.build().getStatus());
+    }
+
+    @Test
+    void Wait() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.wait(Integer.valueOf(1000));
+        Assertions.assertEquals(1000, builder.build().getWait());
+    }
+
+    @Test
+    void isDefault() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.isDefault(true);
+        Assertions.assertTrue(builder.build().isDefault());
+    }
+
+    @Test
+    void build() {
+        ProviderBuilder builder = new ProviderBuilder();
+        builder.host("host").port(8080).contextPath("contextpath").threadPool("mockthreadpool")
+                .threads(2).ioThreads(3).queues(4).accepts(5).codec("mockcodec")
+                .charset("utf-8").payload(6).buffer(1024).transporter("mocktransporter").exchanger("mockexchanger")
+                .dispatcher("mockdispatcher").networker("networker").server("server").client("client")
+                .telnet("mocktelnethandler").prompt("prompt").status("mockstatuschecker").wait(Integer.valueOf(1000))
+                .isDefault(true).id("id").prefix("prefix");
+
+        ProviderConfig config = builder.build();
+        ProviderConfig config2 = builder.build();
+
+        Assertions.assertEquals(8080, config.getPort());
+        Assertions.assertEquals(2, config.getThreads());
+        Assertions.assertEquals(3, config.getIothreads());
+        Assertions.assertEquals(4, config.getQueues());
+        Assertions.assertEquals(5, config.getAccepts());
+        Assertions.assertEquals(6, config.getPayload());
+        Assertions.assertEquals(1024, config.getBuffer());
+        Assertions.assertEquals(1000, config.getWait());
+        Assertions.assertEquals("host", config.getHost());
+        Assertions.assertEquals("contextpath", config.getContextpath());
+        Assertions.assertEquals("mockthreadpool", config.getThreadpool());
+        Assertions.assertEquals("mockcodec", config.getCodec());
+        Assertions.assertEquals("utf-8", config.getCharset());
+        Assertions.assertEquals("mocktransporter", config.getTransporter());
+        Assertions.assertEquals("mockexchanger", config.getExchanger());
+        Assertions.assertEquals("mockdispatcher", config.getDispatcher());
+        Assertions.assertEquals("networker", config.getNetworker());
+        Assertions.assertEquals("server", config.getServer());
+        Assertions.assertEquals("client", config.getClient());
+        Assertions.assertEquals("mocktelnethandler", config.getTelnet());
+        Assertions.assertEquals("prompt", config.getPrompt());
+        Assertions.assertEquals("mockstatuschecker", config.getStatus());
+        Assertions.assertTrue(config.isDefault());
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java
new file mode 100644
index 0000000..4d11ef4
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ReferenceBuilderTest.java
@@ -0,0 +1,125 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.api.DemoService;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+import static org.apache.dubbo.common.utils.CollectionUtils.ofSet;
+
+class ReferenceBuilderTest {
+
+    @Test
+    void interfaceName() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.interfaceName(DemoService.class.getName());
+        Assertions.assertEquals("org.apache.dubbo.config.api.DemoService", builder.build().getInterface());
+    }
+
+    @Test
+    void interfaceClass() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.interfaceClass(DemoService.class);
+        Assertions.assertEquals(DemoService.class, builder.build().getInterfaceClass());
+    }
+
+    @Test
+    void client() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.client("client");
+        Assertions.assertEquals("client", builder.build().getClient());
+    }
+
+    @Test
+    void url() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.url("url");
+        Assertions.assertEquals("url", builder.build().getUrl());
+    }
+
+    @Test
+    void addMethods() {
+        MethodConfig method = new MethodConfig();
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.addMethods(Collections.singletonList(method));
+        Assertions.assertTrue(builder.build().getMethods().contains(method));
+        Assertions.assertEquals(1, builder.build().getMethods().size());
+    }
+
+    @Test
+    void addMethod() {
+        MethodConfig method = new MethodConfig();
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.addMethod(method);
+        Assertions.assertTrue(builder.build().getMethods().contains(method));
+        Assertions.assertEquals(1, builder.build().getMethods().size());
+    }
+
+    @Test
+    void consumer() {
+        ConsumerConfig consumer = new ConsumerConfig();
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.consumer(consumer);
+        Assertions.assertSame(consumer, builder.build().getConsumer());
+    }
+
+    @Test
+    void protocol() {
+        ReferenceBuilder builder = new ReferenceBuilder();
+        builder.protocol("protocol");
+        Assertions.assertEquals("protocol", builder.build().getProtocol());
+    }
+
+    @Test
+    void build() {
+        ConsumerConfig consumer = new ConsumerConfig();
+        MethodConfig method = new MethodConfig();
+
+        ReferenceBuilder<DemoService> builder = new ReferenceBuilder<>();
+        builder.id("id")
+                .interfaceClass(DemoService.class)
+                .protocol("protocol")
+                .client("client")
+                .url("url")
+                .consumer(consumer)
+                .addMethod(method)
+                // introduced since 2.7.8
+                .services("test-service", "test-service2");
+
+        ReferenceConfig config = builder.build();
+        ReferenceConfig config2 = builder.build();
+
+        Assertions.assertEquals("org.apache.dubbo.config.api.DemoService", config.getInterface());
+        Assertions.assertEquals(DemoService.class, config.getInterfaceClass());
+        Assertions.assertEquals("protocol", config.getProtocol());
+        Assertions.assertEquals("client", config.getClient());
+        Assertions.assertEquals("url", config.getUrl());
+        Assertions.assertEquals(consumer, config.getConsumer());
+        Assertions.assertEquals("test-service,test-service2", config.getServices());
+        Assertions.assertEquals(ofSet("test-service", "test-service2"), config.getSubscribedServices());
+        Assertions.assertTrue(config.getMethods().contains(method));
+        Assertions.assertEquals(1, config.getMethods().size());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java
new file mode 100644
index 0000000..b125547
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/RegistryBuilderTest.java
@@ -0,0 +1,256 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.RegistryConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+class RegistryBuilderTest {
+
+    @Test
+    void address() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.address("address");
+        Assertions.assertEquals("address", builder.build().getAddress());
+    }
+
+    @Test
+    void username() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.username("username");
+        Assertions.assertEquals("username", builder.build().getUsername());
+    }
+
+    @Test
+    void password() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.password("password");
+        Assertions.assertEquals("password", builder.build().getPassword());
+    }
+
+    @Test
+    void port() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.port(8080);
+        Assertions.assertEquals(8080, builder.build().getPort());
+    }
+
+    @Test
+    void protocol() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.protocol("protocol");
+        Assertions.assertEquals("protocol", builder.build().getProtocol());
+    }
+
+    @Test
+    void transporter() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.transporter("transporter");
+        Assertions.assertEquals("transporter", builder.build().getTransporter());
+    }
+
+    @Test
+    void transport() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.transport("transport");
+        Assertions.assertEquals("transport", builder.build().getTransport());
+    }
+
+    @Test
+    void server() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.server("server");
+        Assertions.assertEquals("server", builder.build().getServer());
+    }
+
+    @Test
+    void client() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.client("client");
+        Assertions.assertEquals("client", builder.build().getClient());
+    }
+
+    @Test
+    void cluster() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.cluster("cluster");
+        Assertions.assertEquals("cluster", builder.build().getCluster());
+    }
+
+    @Test
+    void group() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.group("group");
+        Assertions.assertEquals("group", builder.build().getGroup());
+    }
+
+    @Test
+    void version() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.version("version");
+        Assertions.assertEquals("version", builder.build().getVersion());
+    }
+
+    @Test
+    void timeout() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.timeout(1000);
+        Assertions.assertEquals(1000, builder.build().getTimeout());
+    }
+
+    @Test
+    void session() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.session(2000);
+        Assertions.assertEquals(2000, builder.build().getSession());
+    }
+
+    @Test
+    void file() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.file("file");
+        Assertions.assertEquals("file", builder.build().getFile());
+    }
+
+    @Test
+    void testWait() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.wait(Integer.valueOf(1000));
+        Assertions.assertEquals(1000, builder.build().getWait());
+    }
+
+    @Test
+    void isCheck() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.isCheck(true);
+        Assertions.assertTrue(builder.build().isCheck());
+    }
+
+    @Test
+    void isDynamic() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.isDynamic(true);
+        Assertions.assertTrue(builder.build().isDynamic());
+    }
+
+    @Test
+    void register() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.register(true);
+        Assertions.assertTrue(builder.build().isRegister());
+    }
+
+    @Test
+    void subscribe() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.subscribe(true);
+        Assertions.assertTrue(builder.build().isSubscribe());
+    }
+
+    @Test
+    void appendParameter() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.appendParameter("default.num", "one").appendParameter("num", "ONE");
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void appendParameters() {
+        Map<String, String> source = new HashMap<>();
+        source.put("default.num", "one");
+        source.put("num", "ONE");
+
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.appendParameters(source);
+
+        Map<String, String> parameters = builder.build().getParameters();
+
+        Assertions.assertTrue(parameters.containsKey("default.num"));
+        Assertions.assertEquals("ONE", parameters.get("num"));
+    }
+
+    @Test
+    void isDefault() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.isDefault(true);
+        Assertions.assertTrue(builder.build().isDefault());
+    }
+
+    @Test
+    void simplified() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.simplified(true);
+        Assertions.assertTrue(builder.build().getSimplified());
+    }
+
+    @Test
+    void extraKeys() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.extraKeys("extraKeys");
+        Assertions.assertEquals("extraKeys", builder.build().getExtraKeys());
+    }
+
+    @Test
+    void build() {
+        RegistryBuilder builder = new RegistryBuilder();
+        builder.address("address").username("username").password("password").port(8080).protocol("protocol")
+                .transporter("transporter").server("server").client("client").cluster("cluster").group("group")
+                .version("version").timeout(1000).session(2000).file("file").wait(Integer.valueOf(10)).isCheck(true)
+                .isDynamic(false).register(true).subscribe(false).isDefault(true).simplified(false).extraKeys("A")
+                .parameter("default.num", "one").id("id").prefix("prefix");
+
+        RegistryConfig config = builder.build();
+        RegistryConfig config2 = builder.build();
+
+        Assertions.assertEquals(8080, config.getPort());
+        Assertions.assertEquals(1000, config.getTimeout());
+        Assertions.assertEquals(2000, config.getSession());
+        Assertions.assertEquals(10, config.getWait());
+        Assertions.assertTrue(config.isCheck());
+        Assertions.assertFalse(config.isDynamic());
+        Assertions.assertTrue(config.isRegister());
+        Assertions.assertFalse(config.isSubscribe());
+        Assertions.assertTrue(config.isDefault());
+        Assertions.assertFalse(config.getSimplified());
+        Assertions.assertEquals("address", config.getAddress());
+        Assertions.assertEquals("username", config.getUsername());
+        Assertions.assertEquals("password", config.getPassword());
+        Assertions.assertEquals("protocol", config.getProtocol());
+        Assertions.assertEquals("transporter", config.getTransporter());
+        Assertions.assertEquals("server", config.getServer());
+        Assertions.assertEquals("client", config.getClient());
+        Assertions.assertEquals("cluster", config.getCluster());
+        Assertions.assertEquals("group", config.getGroup());
+        Assertions.assertEquals("version", config.getVersion());
+        Assertions.assertEquals("file", config.getFile());
+        Assertions.assertEquals("A", config.getExtraKeys());
+        Assertions.assertTrue(config.getParameters().containsKey("default.num"));
+        Assertions.assertEquals("one", config.getParameters().get("default.num"));
+        Assertions.assertEquals("id", config.getId());
+        Assertions.assertEquals("prefix", config.getPrefix());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ServiceBuilderTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ServiceBuilderTest.java
new file mode 100644
index 0000000..ae07c24
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/builders/ServiceBuilderTest.java
@@ -0,0 +1,131 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.builders;
+
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.ServiceConfig;
+
+import org.junit.jupiter.api.Assertions;
+import org.junit.jupiter.api.Test;
+
+import java.util.Collections;
+
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_BEAN;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_DEFAULT;
+import static org.apache.dubbo.common.constants.CommonConstants.GENERIC_SERIALIZATION_NATIVE_JAVA;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+class ServiceBuilderTest {
+
+    @Test
+    void path() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.path("path");
+        Assertions.assertEquals("path", builder.build().getPath());
+    }
+
+    @Test
+    void addMethod() {
+        MethodConfig method = new MethodConfig();
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.addMethod(method);
+        Assertions.assertTrue(builder.build().getMethods().contains(method));
+        Assertions.assertEquals(1, builder.build().getMethods().size());
+    }
+
+    @Test
+    void addMethods() {
+        MethodConfig method = new MethodConfig();
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.addMethods(Collections.singletonList(method));
+        Assertions.assertTrue(builder.build().getMethods().contains(method));
+        Assertions.assertEquals(1, builder.build().getMethods().size());
+    }
+
+    @Test
+    void provider() {
+        ProviderConfig provider = new ProviderConfig();
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.provider(provider);
+        Assertions.assertSame(provider, builder.build().getProvider());
+    }
+
+    @Test
+    void providerIds() {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.providerIds("providerIds");
+        Assertions.assertEquals("providerIds", builder.build().getProviderIds());
+    }
+
+    @Test
+    public void generic() throws Exception {
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.generic(GENERIC_SERIALIZATION_DEFAULT);
+        assertThat(builder.build().getGeneric(), equalTo(GENERIC_SERIALIZATION_DEFAULT));
+        builder.generic(GENERIC_SERIALIZATION_NATIVE_JAVA);
+        assertThat(builder.build().getGeneric(), equalTo(GENERIC_SERIALIZATION_NATIVE_JAVA));
+        builder.generic(GENERIC_SERIALIZATION_BEAN);
+        assertThat(builder.build().getGeneric(), equalTo(GENERIC_SERIALIZATION_BEAN));
+    }
+
+    @Test
+    public void generic1() throws Exception {
+        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+            ServiceBuilder builder = new ServiceBuilder();
+            builder.generic("illegal").build();
+        });
+    }
+//
+//    @Test
+//    public void Mock() throws Exception {
+//        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+//            ServiceBuilder builder = new ServiceBuilder();
+//            builder.mock("true");
+//        });
+//    }
+//
+//    @Test
+//    public void Mock1() throws Exception {
+//        Assertions.assertThrows(IllegalArgumentException.class, () -> {
+//            ServiceBuilder builder = new ServiceBuilder();
+//            builder.mock(true);
+//        });
+//    }
+
+    @Test
+    void build() {
+        MethodConfig method = new MethodConfig();
+        ProviderConfig provider = new ProviderConfig();
+
+        ServiceBuilder builder = new ServiceBuilder();
+        builder.path("path").addMethod(method).provider(provider).providerIds("providerIds")
+                .generic(GENERIC_SERIALIZATION_DEFAULT);
+
+        ServiceConfig config = builder.build();
+        ServiceConfig config2 = builder.build();
+
+        assertThat(config.getGeneric(), equalTo(GENERIC_SERIALIZATION_DEFAULT));
+        Assertions.assertEquals("path", config.getPath());
+        Assertions.assertEquals("providerIds", config.getProviderIds());
+        Assertions.assertSame(provider, config.getProvider());
+        Assertions.assertTrue(config.getMethods().contains(method));
+        Assertions.assertEquals(1, config.getMethods().size());
+        Assertions.assertNotSame(config, config2);
+    }
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/compatible/DubboInterfaceConsumerBootstrap.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/compatible/DubboInterfaceConsumerBootstrap.java
new file mode 100644
index 0000000..738a881
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/compatible/DubboInterfaceConsumerBootstrap.java
@@ -0,0 +1,57 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.bootstrap.compatible;
+
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.bootstrap.DubboBootstrap;
+import org.apache.dubbo.config.bootstrap.EchoService;
+import org.apache.dubbo.config.bootstrap.rest.UserService;
+
+/**
+ * Dubbo Provider Bootstrap
+ *
+ * @since 2.7.5
+ */
+public class DubboInterfaceConsumerBootstrap {
+
+    public static void main(String[] args) throws Exception {
+        RegistryConfig interfaceRegistry = new RegistryConfig();
+        interfaceRegistry.setId("interfaceRegistry");
+        interfaceRegistry.setAddress("zookeeper://127.0.0.1:2181");
+
+        DubboBootstrap bootstrap = DubboBootstrap.getInstance()
+                .application("dubbo-consumer-demo")
+                // Zookeeper
+                .registry(interfaceRegistry)
+                // Nacos
+//                .registry("consul", builder -> builder.address("consul://127.0.0.1:8500?registry.type=service&subscribed.services=dubbo-provider-demo"))
+                .reference("echo", builder -> builder.interfaceClass(EchoService.class).protocol("dubbo"))
+                .reference("user", builder -> builder.interfaceClass(UserService.class).protocol("rest"))
+                .start()
+                .await();
+
+        EchoService echoService = bootstrap.getCache().get(EchoService.class);
+        UserService userService = bootstrap.getCache().get(UserService.class);
+
+        for (int i = 0; i < 500; i++) {
+            Thread.sleep(2000L);
+            System.out.println(echoService.echo("Hello,World"));
+            System.out.println(userService.getUser(1L));
+        }
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/User.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/User.java
new file mode 100644
index 0000000..cfd52e2
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/User.java
@@ -0,0 +1,77 @@
+/*
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.dubbo.config.bootstrap.rest;
+
+import org.codehaus.jackson.annotate.JsonProperty;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Size;
+import javax.xml.bind.annotation.XmlAccessType;
+import javax.xml.bind.annotation.XmlAccessorType;
+import javax.xml.bind.annotation.XmlElement;
+import javax.xml.bind.annotation.XmlRootElement;
+import java.io.Serializable;
+
+@XmlRootElement
+@XmlAccessorType(XmlAccessType.FIELD)
+public class User implements Serializable {
+
+    @NotNull
+    @Min(1L)
+    private Long id;
+
+    @JsonProperty("username")
+    @XmlElement(name = "username")
+    @NotNull
+    @Size(min = 6, max = 50)
+    private String name;
+
+    public User() {
+    }
+
+    public User(Long id, String name) {
+        this.id = id;
+        this.name = name;
+    }
+
+    public Long getId() {
+        return id;
+    }
+
+    public void setId(Long id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    @Override
+    public String toString() {
+        return "User (" +
+                "id=" + id +
+                ", name='" + name + '\'' +
+                ')';
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java
new file mode 100644
index 0000000..fa5b7ae
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserService.java
@@ -0,0 +1,45 @@
+/*
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.dubbo.config.bootstrap.rest;
+
+
+import org.apache.dubbo.rpc.protocol.rest.support.ContentType;
+
+import io.swagger.annotations.Api;
+import io.swagger.annotations.ApiOperation;
+import io.swagger.annotations.ApiParam;
+
+import javax.ws.rs.Consumes;
+import javax.ws.rs.GET;
+import javax.ws.rs.Path;
+import javax.ws.rs.PathParam;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.MediaType;
+
+@Path("users")
+@Consumes({MediaType.APPLICATION_JSON, MediaType.TEXT_XML})
+@Produces({ContentType.APPLICATION_JSON_UTF_8, ContentType.TEXT_XML_UTF_8})
+@Api(value = "UserService")
+public interface UserService {
+
+    @GET
+    @Path("{id : \\d+}")
+    @ApiOperation(value = "getUser")
+    User getUser(@ApiParam(value = "id") @PathParam("id") Long id);
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserServiceImpl.java b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserServiceImpl.java
new file mode 100644
index 0000000..8cb0bd0
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/bootstrap/rest/UserServiceImpl.java
@@ -0,0 +1,32 @@
+/*
+ *
+ *   Licensed to the Apache Software Foundation (ASF) under one or more
+ *   contributor license agreements.  See the NOTICE file distributed with
+ *   this work for additional information regarding copyright ownership.
+ *   The ASF licenses this file to You under the Apache License, Version 2.0
+ *   (the "License"); you may not use this file except in compliance with
+ *   the License.  You may obtain a copy of the License at
+ *
+ *       http://www.apache.org/licenses/LICENSE-2.0
+ *
+ *   Unless required by applicable law or agreed to in writing, software
+ *   distributed under the License is distributed on an "AS IS" BASIS,
+ *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ *   See the License for the specific language governing permissions and
+ *   limitations under the License.
+ *
+ */
+package org.apache.dubbo.config.bootstrap.rest;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class UserServiceImpl implements UserService {
+
+    private final AtomicLong idGen = new AtomicLong();
+
+    @Override
+    public User getUser(Long id) {
+        return new User(id, "username" + id);
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheService.java b/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheService.java
new file mode 100644
index 0000000..7696b24
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheService.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.cache;
+
+/**
+ * ValidationService
+ */
+public interface CacheService {
+
+    String findCache(String id);
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheServiceImpl.java b/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheServiceImpl.java
new file mode 100644
index 0000000..14e9ee7
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheServiceImpl.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.cache;
+
+import java.util.concurrent.atomic.AtomicInteger;
+
+/**
+ * ValidationServiceImpl
+ */
+public class CacheServiceImpl implements CacheService {
+
+    private final AtomicInteger i = new AtomicInteger();
+
+    public String findCache(String id) {
+        return "request: " + id + ", response: " + i.getAndIncrement();
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheTest.java
new file mode 100644
index 0000000..ed7cb5e
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/cache/CacheTest.java
@@ -0,0 +1,140 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.cache;
+
+import org.apache.dubbo.cache.Cache;
+import org.apache.dubbo.cache.CacheFactory;
+import org.apache.dubbo.cache.support.threadlocal.ThreadLocalCache;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.RpcInvocation;
+
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+/**
+ * CacheTest
+ */
+public class CacheTest {
+
+    @BeforeEach
+    public void setUp() {
+//        ApplicationModel.getConfigManager().clear();
+    }
+
+    @AfterEach
+    public void tearDown() {
+//        ApplicationModel.getConfigManager().clear();
+    }
+
+    private void testCache(String type) throws Exception {
+        ApplicationConfig applicationConfig = new ApplicationConfig("cache-test");
+        RegistryConfig registryConfig = new RegistryConfig("N/A");
+        ProtocolConfig protocolConfig = new ProtocolConfig("injvm");
+        ServiceConfig<CacheService> service = new ServiceConfig<CacheService>();
+        service.setApplication(applicationConfig);
+        service.setRegistry(registryConfig);
+        service.setProtocol(protocolConfig);
+        service.setInterface(CacheService.class.getName());
+        service.setRef(new CacheServiceImpl());
+        service.export();
+        try {
+            ReferenceConfig<CacheService> reference = new ReferenceConfig<CacheService>();
+            reference.setApplication(applicationConfig);
+            reference.setInterface(CacheService.class);
+            reference.setUrl("injvm://127.0.0.1?scope=remote&cache=true");
+
+            MethodConfig method = new MethodConfig();
+            method.setName("findCache");
+            method.setCache(type);
+            reference.setMethods(Arrays.asList(method));
+
+            CacheService cacheService = reference.get();
+            try {
+                // verify cache, same result is returned for multiple invocations (in fact, the return value increases
+                // on every invocation on the server side)
+                String fix = null;
+                for (int i = 0; i < 3; i++) {
+                    String result = cacheService.findCache("0");
+                    assertTrue(fix == null || fix.equals(result));
+                    fix = result;
+                    Thread.sleep(100);
+                }
+
+                if ("lru".equals(type)) {
+                    // default cache.size is 1000 for LRU, should have cache expired if invoke more than 1001 times
+                    for (int n = 0; n < 1001; n++) {
+                        String pre = null;
+                        for (int i = 0; i < 10; i++) {
+                            String result = cacheService.findCache(String.valueOf(n));
+                            assertTrue(pre == null || pre.equals(result));
+                            pre = result;
+                        }
+                    }
+
+                    // verify if the first cache item is expired in LRU cache
+                    String result = cacheService.findCache("0");
+                    assertFalse(fix == null || fix.equals(result));
+                }
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+    @Test
+    public void testCacheLru() throws Exception {
+        testCache("lru");
+    }
+
+    @Test
+    public void testCacheThreadlocal() throws Exception {
+        testCache("threadlocal");
+    }
+
+    @Test
+    public void testCacheProvider() throws Exception {
+        CacheFactory cacheFactory = ExtensionLoader.getExtensionLoader(CacheFactory.class).getAdaptiveExtension();
+
+        Map<String, String> parameters = new HashMap<String, String>();
+        parameters.put("findCache.cache", "threadlocal");
+        URL url = new URL("dubbo", "127.0.0.1", 29582, "org.apache.dubbo.config.cache.CacheService", parameters);
+
+        Invocation invocation = new RpcInvocation("findCache", CacheService.class.getName(), "", new Class[]{String.class}, new String[]{"0"}, null, null, null);
+
+        Cache cache = cacheFactory.getCache(url, invocation);
+        assertTrue(cache instanceof ThreadLocalCache);
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoActionByAnnotation.java b/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoActionByAnnotation.java
new file mode 100644
index 0000000..23d00e4
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoActionByAnnotation.java
@@ -0,0 +1,35 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.consumer;
+
+import org.apache.dubbo.config.api.DemoService;
+
+import org.springframework.beans.factory.annotation.Autowired;
+
+/**
+ * DemoAction
+ */
+public class DemoActionByAnnotation {
+
+    @Autowired
+    private DemoService demoService;
+
+    public DemoService getDemoService() {
+        return demoService;
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoActionBySetter.java b/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoActionBySetter.java
new file mode 100644
index 0000000..0606e26
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoActionBySetter.java
@@ -0,0 +1,36 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.consumer;
+
+import org.apache.dubbo.config.api.DemoService;
+
+/**
+ * DemoAction
+ */
+public class DemoActionBySetter {
+
+    private DemoService demoService;
+
+    public DemoService getDemoService() {
+        return demoService;
+    }
+
+    public void setDemoService(DemoService demoService) {
+        this.demoService = demoService;
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoInterceptor.java b/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoInterceptor.java
new file mode 100644
index 0000000..46d7e9a
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/consumer/DemoInterceptor.java
@@ -0,0 +1,31 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.consumer;
+
+import org.aopalliance.intercept.MethodInterceptor;
+import org.aopalliance.intercept.MethodInvocation;
+
+/**
+ * DemoInterceptor
+ */
+public class DemoInterceptor implements MethodInterceptor {
+
+    public Object invoke(MethodInvocation invocation) throws Throwable {
+        return "aop:" + invocation.proceed();
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListenerTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListenerTest.java
new file mode 100644
index 0000000..e7e5376
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/event/listener/PublishingServiceDefinitionListenerTest.java
@@ -0,0 +1,94 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.event.listener;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.bootstrap.EchoService;
+import org.apache.dubbo.config.bootstrap.EchoServiceImpl;
+import org.apache.dubbo.config.context.ConfigManager;
+import org.apache.dubbo.config.event.ServiceConfigExportedEvent;
+import org.apache.dubbo.metadata.WritableMetadataService;
+import org.apache.dubbo.metadata.definition.model.FullServiceDefinition;
+import org.apache.dubbo.rpc.model.ApplicationModel;
+
+import com.google.gson.Gson;
+import org.junit.jupiter.api.AfterEach;
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+
+import java.util.List;
+
+import static org.apache.dubbo.common.constants.CommonConstants.DEFAULT_METADATA_STORAGE_TYPE;
+import static org.apache.dubbo.common.constants.CommonConstants.PID_KEY;
+import static org.apache.dubbo.common.constants.CommonConstants.TIMESTAMP_KEY;
+import static org.apache.dubbo.metadata.definition.ServiceDefinitionBuilder.buildFullDefinition;
+import static org.apache.dubbo.remoting.Constants.BIND_IP_KEY;
+import static org.apache.dubbo.remoting.Constants.BIND_PORT_KEY;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+
+/**
+ * {@link PublishingServiceDefinitionListener} Test-Cases
+ *
+ * @since 2.7.8
+ */
+public class PublishingServiceDefinitionListenerTest {
+
+    private WritableMetadataService writableMetadataService;
+
+    @BeforeEach
+    public void init() {
+        String metadataType = DEFAULT_METADATA_STORAGE_TYPE;
+        ConfigManager configManager = ApplicationModel.getConfigManager();
+        ApplicationConfig applicationConfig = new ApplicationConfig("dubbo-demo-provider");
+        applicationConfig.setMetadataType(metadataType);
+        configManager.setApplication(applicationConfig);
+        this.writableMetadataService = WritableMetadataService.getDefaultExtension();
+    }
+
+    @AfterEach
+    public void reset() {
+        ApplicationModel.reset();
+    }
+
+    /**
+     * Test {@link ServiceConfigExportedEvent} arising
+     */
+    @Test
+    public void testOnServiceConfigExportedEvent() {
+        ServiceConfig<EchoService> serviceConfig = new ServiceConfig<>();
+        serviceConfig.setInterface(EchoService.class);
+        serviceConfig.setRef(new EchoServiceImpl());
+        serviceConfig.setRegistry(new RegistryConfig("N/A"));
+        serviceConfig.export();
+
+        String serviceDefinition = writableMetadataService.getServiceDefinition(EchoService.class.getName());
+
+        List<URL> exportedUrls = serviceConfig.getExportedUrls();
+
+        FullServiceDefinition fullServiceDefinition = buildFullDefinition(
+                serviceConfig.getInterfaceClass(),
+                exportedUrls.get(0)
+                        .removeParameters(PID_KEY, TIMESTAMP_KEY, BIND_IP_KEY, BIND_PORT_KEY, TIMESTAMP_KEY)
+                        .getParameters()
+        );
+
+        assertEquals(serviceDefinition, new Gson().toJson(fullServiceDefinition));
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java b/dubbo-test/src/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java
new file mode 100644
index 0000000..a8cd438
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java
@@ -0,0 +1,60 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config.invoker;
+
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+
+import org.junit.jupiter.api.BeforeEach;
+import org.junit.jupiter.api.Test;
+import org.mockito.Mockito;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.Matchers.sameInstance;
+
+public class DelegateProviderMetaDataInvokerTest {
+    private ServiceConfig service;
+    private Invoker<Greeting> invoker;
+
+    @BeforeEach
+    public void setUp() throws Exception {
+        service = Mockito.mock(ServiceConfig.class);
+        invoker = Mockito.mock(Invoker.class);
+    }
+
+    @Test
+    public void testDelegate() throws Exception {
+        DelegateProviderMetaDataInvoker<Greeting> delegate =
+                new DelegateProviderMetaDataInvoker<Greeting>(invoker, service);
+        delegate.getInterface();
+        Mockito.verify(invoker).getInterface();
+        delegate.getUrl();
+        Mockito.verify(invoker).getUrl();
+        delegate.isAvailable();
+        Mockito.verify(invoker).isAvailable();
+        Invocation invocation = Mockito.mock(Invocation.class);
+        delegate.invoke(invocation);
+        Mockito.verify(invoker).invoke(invocation);
+        delegate.destroy();
+        Mockito.verify(invoker).destroy();
+        assertThat(delegate.getMetadata(), sameInstance(service));
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal1.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal1.java
new file mode 100644
index 0000000..f3d5ee5
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal1.java
@@ -0,0 +1,21 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+public class GreetingLocal1 {
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal2.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal2.java
new file mode 100644
index 0000000..8cae406
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal2.java
@@ -0,0 +1,26 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.config.api.Greeting;
+
+public class GreetingLocal2 implements Greeting {
+    @Override
+    public String hello() {
+        return "local";
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal3.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal3.java
new file mode 100644
index 0000000..9b14ac6
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingLocal3.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.config.api.Greeting;
+
+public class GreetingLocal3 implements Greeting {
+    private Greeting greeting;
+
+    public GreetingLocal3(Greeting greeting) {
+        this.greeting = greeting;
+    }
+
+    @Override
+    public String hello() {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingMock1.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingMock1.java
new file mode 100644
index 0000000..8bfe6e6
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingMock1.java
@@ -0,0 +1,20 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+public class GreetingMock1 {
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingMock2.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingMock2.java
new file mode 100644
index 0000000..429bff4
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/GreetingMock2.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.config.api.Greeting;
+
+public class GreetingMock2 implements Greeting {
+    private GreetingMock2() {
+    }
+
+    @Override
+    public String hello() {
+        return "mock";
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
new file mode 100644
index 0000000..39bf974
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockCluster.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.Cluster;
+import org.apache.dubbo.rpc.cluster.Directory;
+
+public class MockCluster implements Cluster {
+    @Override
+    public <T> Invoker<T> join(Directory<T> directory) throws RpcException {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockCodec.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockCodec.java
new file mode 100644
index 0000000..c1aac42
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockCodec.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.remoting.Channel;
+import org.apache.dubbo.remoting.Codec;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
+
+public class MockCodec implements Codec {
+    @Override
+    public void encode(Channel channel, OutputStream output, Object message) throws IOException {
+
+    }
+
+    @Override
+    public Object decode(Channel channel, InputStream input) throws IOException {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockDispatcher.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockDispatcher.java
new file mode 100644
index 0000000..32fffca
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockDispatcher.java
@@ -0,0 +1,29 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.ChannelHandler;
+import org.apache.dubbo.remoting.Dispatcher;
+
+public class MockDispatcher implements Dispatcher {
+    @Override
+    public ChannelHandler dispatch(ChannelHandler handler, URL url) {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockExchanger.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockExchanger.java
new file mode 100644
index 0000000..fccfd23
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockExchanger.java
@@ -0,0 +1,37 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.remoting.RemotingException;
+import org.apache.dubbo.remoting.exchange.ExchangeClient;
+import org.apache.dubbo.remoting.exchange.ExchangeHandler;
+import org.apache.dubbo.remoting.exchange.ExchangeServer;
+import org.apache.dubbo.remoting.exchange.Exchanger;
+
+public class MockExchanger implements Exchanger {
+    @Override
+    public ExchangeServer bind(URL url, ExchangeHandler handler) throws RemotingException {
+        return null;
+    }
+
+    @Override
+    public ExchangeClient connect(URL url, ExchangeHandler handler) throws RemotingException {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockExporterListener.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockExporterListener.java
new file mode 100644
index 0000000..b93f44c
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockExporterListener.java
@@ -0,0 +1,34 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.ExporterListener;
+import org.apache.dubbo.rpc.RpcException;
+
+public class MockExporterListener implements ExporterListener {
+    @Override
+    public void exported(Exporter<?> exporter) throws RpcException {
+
+    }
+
+    @Override
+    public void unexported(Exporter<?> exporter) {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockFilter.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockFilter.java
new file mode 100644
index 0000000..d51f123
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockFilter.java
@@ -0,0 +1,30 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.rpc.Filter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+
+public class MockFilter implements Filter {
+    @Override
+    public Result invoke(Invoker<?> invoker, Invocation invocation) throws RpcException {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockInvokerListener.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockInvokerListener.java
new file mode 100644
index 0000000..c929e54
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockInvokerListener.java
@@ -0,0 +1,33 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.InvokerListener;
+import org.apache.dubbo.rpc.RpcException;
+
+public class MockInvokerListener implements InvokerListener {
+    @Override
+    public void referred(Invoker<?> invoker) throws RpcException {
+
+    }
+
+    @Override
+    public void destroyed(Invoker<?> invoker) {
+
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockLoadBalance.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockLoadBalance.java
new file mode 100644
index 0000000..377f328
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockLoadBalance.java
@@ -0,0 +1,32 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.cluster.LoadBalance;
+
+import java.util.List;
+
+public class MockLoadBalance implements LoadBalance {
+    @Override
+    public <T> Invoker<T> select(List<Invoker<T>> invokers, URL url, Invocation invocation) throws RpcException {
+        return null;
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProtocol.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProtocol.java
new file mode 100644
index 0000000..2ab518c
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProtocol.java
@@ -0,0 +1,89 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invocation;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.Result;
+import org.apache.dubbo.rpc.RpcException;
+
+import org.mockito.Mockito;
+
+public class MockProtocol implements Protocol {
+
+    /* (non-Javadoc)
+     * @see org.apache.dubbo.rpc.Protocol#getDefaultPort()
+     */
+    @Override
+    public int getDefaultPort() {
+
+        return 0;
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.dubbo.rpc.Protocol#export(org.apache.dubbo.rpc.Invoker)
+     */
+    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
+        return Mockito.mock(Exporter.class);
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.dubbo.rpc.Protocol#refer(java.lang.Class, org.apache.dubbo.common.URL)
+     */
+    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
+
+        final URL u = url;
+
+        return new Invoker<T>() {
+            @Override
+            public Class<T> getInterface() {
+                return null;
+            }
+
+            public URL getUrl() {
+                return u;
+            }
+
+            @Override
+            public boolean isAvailable() {
+                return true;
+            }
+
+            @Override
+            public Result invoke(Invocation invocation) throws RpcException {
+                return null;
+            }
+
+            @Override
+            public void destroy() {
+
+            }
+        };
+    }
+
+    /* (non-Javadoc)
+     * @see org.apache.dubbo.rpc.Protocol#destroy()
+     */
+    @Override
+    public void destroy() {
+
+    }
+
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProtocol2.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProtocol2.java
new file mode 100644
index 0000000..91653d4
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProtocol2.java
@@ -0,0 +1,48 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Exporter;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.Protocol;
+import org.apache.dubbo.rpc.RpcException;
+
+public class MockProtocol2 implements Protocol {
+    public static Protocol delegate;
+
+    @Override
+    public int getDefaultPort() {
+        return delegate.getDefaultPort();
+    }
+
+    @Override
+    public <T> Exporter<T> export(Invoker<T> invoker) throws RpcException {
+        return delegate.export(invoker);
+    }
+
+    @Override
+    public <T> Invoker<T> refer(Class<T> type, URL url) throws RpcException {
+        return delegate.refer(type, url);
+    }
+
+    @Override
+    public void destroy() {
+        delegate.destroy();
+    }
+}
diff --git a/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProxyFactory.java b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProxyFactory.java
new file mode 100644
index 0000000..49f05d8
--- /dev/null
+++ b/dubbo-test/src/test/java/org/apache/dubbo/config/mock/MockProxyFactory.java
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements.  See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License.  You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.apache.dubbo.config.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.ProxyFactory;
+import org.apache.dubbo.rpc.RpcException;
... 2019 lines suppressed ...