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 2018/11/01 07:20:12 UTC

[incubator-dubbo] 03/06: Move UT in config-api to bootstrap temporarily, to solve the unreasonable dependency problem between modules.

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

liujun pushed a commit to branch dev-metadata
in repository https://gitbox.apache.org/repos/asf/incubator-dubbo.git

commit a45bfd4f3a92af11f8a13aee6439d5a32ae5c5fc
Author: ken.lj <ke...@gmail.com>
AuthorDate: Thu Nov 1 10:50:32 2018 +0800

    Move UT in config-api to bootstrap temporarily, to solve the unreasonable dependency problem between modules.
---
 .../apache/dubbo/config/AbstractConfigTest.java    | 515 +++++++++++++++++++++
 .../dubbo/config/AbstractInterfaceConfigTest.java  | 407 ++++++++++++++++
 .../dubbo/config/AbstractMethodConfigTest.java     | 119 +++++
 .../dubbo/config/AbstractReferenceConfigTest.java  | 157 +++++++
 .../dubbo/config/AbstractServiceConfigTest.java    | 181 ++++++++
 .../apache/dubbo/config/ApplicationConfigTest.java | 177 +++++++
 .../apache/dubbo/config/ArgumentConfigTest.java    |  63 +++
 .../apache/dubbo/config/ConsumerConfigTest.java    |  81 ++++
 .../apache/dubbo/config/GenericServiceTest.java    | 314 +++++++++++++
 .../org/apache/dubbo/config/MethodConfigTest.java  | 182 ++++++++
 .../org/apache/dubbo/config/ModuleConfigTest.java  | 110 +++++
 .../org/apache/dubbo/config/MonitorConfigTest.java | 107 +++++
 .../apache/dubbo/config/ProtocolConfigTest.java    | 217 +++++++++
 .../apache/dubbo/config/ProviderConfigTest.java    | 219 +++++++++
 .../apache/dubbo/config/ReferenceConfigTest.java   | 108 +++++
 .../apache/dubbo/config/RegistryConfigTest.java    | 178 +++++++
 .../org/apache/dubbo/config/ServiceConfigTest.java | 205 ++++++++
 .../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 +++
 .../apache/dubbo/config/cache/CacheService.java    |  26 ++
 .../dubbo/config/cache/CacheServiceImpl.java       |  32 ++
 .../org/apache/dubbo/config/cache/CacheTest.java   | 118 +++++
 .../config/consumer/DemoActionByAnnotation.java    |  34 ++
 .../dubbo/config/consumer/DemoActionBySetter.java  |  36 ++
 .../dubbo/config/consumer/DemoInterceptor.java     |  31 ++
 .../DelegateProviderMetaDataInvokerTest.java       |  59 +++
 .../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 |  86 ++++
 .../apache/dubbo/config/mock/MockProtocol2.java    |  48 ++
 .../apache/dubbo/config/mock/MockProxyFactory.java |  39 ++
 .../org/apache/dubbo/config/mock/MockRegistry.java | 108 +++++
 .../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  |  41 ++
 .../apache/dubbo/config/mock/TestProxyFactory.java |  33 ++
 .../config/provider/impl/DemoServiceImpl.java      |  51 ++
 .../config/url/ExporterSideConfigUrlTest.java      |  98 ++++
 .../dubbo/config/url/InvokerSideConfigUrlTest.java | 227 +++++++++
 .../dubbo/config/url/RpcConfigGetSetProxy.java     | 166 +++++++
 .../org/apache/dubbo/config/url/UrlTestBase.java   | 211 +++++++++
 .../dubbo/config/utils/MockReferenceConfig.java    |  53 +++
 .../config/utils/ReferenceConfigCacheTest.java     | 114 +++++
 .../config/validation/ValidationParameter.java     | 106 +++++
 .../dubbo/config/validation/ValidationService.java |  70 +++
 .../config/validation/ValidationServiceImpl.java   |  37 ++
 .../dubbo/config/validation/ValidationTest.java    | 301 ++++++++++++
 .../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-bootstrap/src/main/test/resources/log4j.xml  |  28 ++
 80 files changed, 6382 insertions(+)

diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractConfigTest.java
new file mode 100644
index 0000000..a9300ec
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractConfigTest.java
@@ -0,0 +1,515 @@
+/*
+ * 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 junit.framework.TestCase;
+import org.apache.dubbo.config.api.Greeting;
+import org.apache.dubbo.config.support.Parameter;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.junit.Assert.assertThat;
+
+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);
+            TestCase.assertEquals(1, config.getI());
+            TestCase.assertEquals('c', config.getC());
+            TestCase.assertEquals((byte) 0x02, config.getB());
+            TestCase.assertEquals(3d, config.getD());
+            TestCase.assertEquals(4f, config.getF());
+            TestCase.assertEquals(5L, config.getL());
+            TestCase.assertEquals(6, config.getS());
+            TestCase.assertEquals("dubbo", config.getStr());
+            TestCase.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);
+            TestCase.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);
+            TestCase.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("default.num", "one");
+        parameters.put("num", "ONE");
+        AbstractConfig.appendParameters(parameters, new ParameterConfig(1, "hello/world", 30, "password"), "prefix");
+        TestCase.assertEquals("one", parameters.get("prefix.key.1"));
+        TestCase.assertEquals("two", parameters.get("prefix.key.2"));
+        TestCase.assertEquals("ONE,one,1", parameters.get("prefix.num"));
+        TestCase.assertEquals("hello%2Fworld", parameters.get("prefix.naming"));
+        TestCase.assertEquals("30", parameters.get("prefix.age"));
+        TestCase.assertFalse(parameters.containsKey("prefix.key-2"));
+        TestCase.assertFalse(parameters.containsKey("prefix.secret"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testAppendParameters2() throws Exception {
+        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);
+        TestCase.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"));
+        TestCase.assertEquals("one", parameters.get("key.1"));
+        TestCase.assertEquals("two", parameters.get("key.2"));
+        TestCase.assertEquals("1", parameters.get("num"));
+        TestCase.assertEquals("hello%2Fworld", parameters.get("naming"));
+        TestCase.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");
+        TestCase.assertEquals('l', parameters.get("prefix.let"));
+        TestCase.assertEquals(true, parameters.get("prefix.activate"));
+        TestCase.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));
+        TestCase.assertEquals('l', parameters.get("let"));
+        TestCase.assertEquals(true, parameters.get("activate"));
+        TestCase.assertFalse(parameters.containsKey("flag"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkExtension() throws Exception {
+        AbstractConfig.checkExtension(Greeting.class, "hello", "world");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkMultiExtension1() throws Exception {
+        AbstractConfig.checkMultiExtension(Greeting.class, "hello", "default,world");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkMultiExtension2() throws Exception {
+        AbstractConfig.checkMultiExtension(Greeting.class, "hello", "default,-world");
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkLength() throws Exception {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i <= 200; i++) {
+            builder.append("a");
+        }
+        AbstractConfig.checkLength("hello", builder.toString());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkPathLength() throws Exception {
+        StringBuilder builder = new StringBuilder();
+        for (int i = 0; i <= 200; i++) {
+            builder.append("a");
+        }
+        AbstractConfig.checkPathLength("hello", builder.toString());
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkName() throws Exception {
+        AbstractConfig.checkName("hello", "world%");
+    }
+
+    @Test
+    public void checkNameHasSymbol() throws Exception {
+        try {
+            AbstractConfig.checkNameHasSymbol("hello", ":*,/-0123abcdABCD");
+        } catch (Exception e) {
+            TestCase.fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkKey() throws Exception {
+        try {
+            AbstractConfig.checkKey("hello", "*,-0123abcdABCD");
+        } catch (Exception e) {
+            TestCase.fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkMultiName() throws Exception {
+        try {
+            AbstractConfig.checkMultiName("hello", ",-._0123abcdABCD");
+        } catch (Exception e) {
+            TestCase.fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkPathName() throws Exception {
+        try {
+            AbstractConfig.checkPathName("hello", "/-$._0123abcdABCD");
+        } catch (Exception e) {
+            TestCase.fail("the value should be legal.");
+        }
+    }
+
+    @Test
+    public void checkMethodName() throws Exception {
+        try {
+            AbstractConfig.checkMethodName("hello", "abcdABCD0123abcd");
+        } catch (Exception e) {
+            TestCase.fail("the value should be legal.");
+        }
+
+        try {
+            AbstractConfig.checkMethodName("hello", "0a");
+            TestCase.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 {
+            AbstractConfig.checkParameterName(parameters);
+        } catch (Exception e) {
+            TestCase.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);
+        TestCase.assertSame(Greeting.class, annotationConfig.getInterface());
+        TestCase.assertEquals("f1, f2", annotationConfig.getFilter());
+        TestCase.assertEquals("l1, l2", annotationConfig.getListener());
+        TestCase.assertEquals(2, annotationConfig.getParameters().size());
+        TestCase.assertEquals("v1", annotationConfig.getParameters().get("k1"));
+        TestCase.assertEquals("v2", annotationConfig.getParameters().get("k2"));
+        assertThat(annotationConfig.toString(), Matchers.containsString("filter=\"f1, f2\" "));
+        assertThat(annotationConfig.toString(), Matchers.containsString("listener=\"l1, l2\" "));
+    }
+
+    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;
+        }
+    }
+
+    @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 {};
+    }
+
+    private static class AnnotationConfig extends AbstractConfig {
+        private Class interfaceClass;
+        private String filter;
+        private String listener;
+        private Map<String, String> parameters;
+
+        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;
+        }
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java
new file mode 100644
index 0000000..a99a910
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractInterfaceConfigTest.java
@@ -0,0 +1,407 @@
+/*
+ * 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 junit.framework.TestCase;
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.common.utils.ConfigUtils;
+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.monitor.MonitorService;
+import org.apache.dubbo.registry.RegistryService;
+import org.junit.AfterClass;
+import org.junit.BeforeClass;
+import org.junit.ClassRule;
+import org.junit.Test;
+import org.junit.rules.TemporaryFolder;
+
+import java.io.BufferedOutputStream;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.util.Collections;
+import java.util.List;
+import java.util.Properties;
+
+public class AbstractInterfaceConfigTest {
+    @ClassRule
+    public static TemporaryFolder tempDir = new TemporaryFolder();
+    private static File dubboProperties;
+
+    @BeforeClass
+    public static void setUp() throws Exception {
+        dubboProperties = tempDir.newFile(Constants.DUBBO_PROPERTIES_KEY);
+        System.setProperty(Constants.DUBBO_PROPERTIES_KEY, dubboProperties.getAbsolutePath());
+    }
+
+    @AfterClass
+    public static void tearDown() throws Exception {
+        System.clearProperty(Constants.DUBBO_PROPERTIES_KEY);
+    }
+
+    @Test
+    public void testCheckRegistry1() throws Exception {
+        System.setProperty("dubbo.registry.address", "addr1|addr2");
+        try {
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkRegistry();
+            TestCase.assertEquals(2, interfaceConfig.getRegistries().size());
+        } finally {
+            System.clearProperty("dubbo.registry.address");
+        }
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void testCheckRegistry2() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkRegistry();
+    }
+
+    @Test
+    public void checkApplication1() throws Exception {
+        try {
+            ConfigUtils.setProperties(null);
+            System.clearProperty(Constants.SHUTDOWN_WAIT_KEY);
+            System.clearProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY);
+
+            writeDubboProperties(Constants.SHUTDOWN_WAIT_KEY, "100");
+            System.setProperty("dubbo.application.name", "demo");
+            InterfaceConfig interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkApplication();
+            ApplicationConfig appConfig = interfaceConfig.getApplication();
+            TestCase.assertEquals("demo", appConfig.getName());
+            TestCase.assertEquals("100", System.getProperty(Constants.SHUTDOWN_WAIT_KEY));
+
+            System.clearProperty(Constants.SHUTDOWN_WAIT_KEY);
+            ConfigUtils.setProperties(null);
+            writeDubboProperties(Constants.SHUTDOWN_WAIT_SECONDS_KEY, "1000");
+            System.setProperty("dubbo.application.name", "demo");
+            interfaceConfig = new InterfaceConfig();
+            interfaceConfig.checkApplication();
+            TestCase.assertEquals("1000", System.getProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY));
+        } finally {
+            ConfigUtils.setProperties(null);
+            System.clearProperty("dubbo.application.name");
+            System.clearProperty(Constants.SHUTDOWN_WAIT_KEY);
+            System.clearProperty(Constants.SHUTDOWN_WAIT_SECONDS_KEY);
+        }
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkApplication2() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkApplication();
+    }
+
+    @Test
+    public void testLoadRegistries() throws Exception {
+        System.setProperty("dubbo.registry.address", "addr1");
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        List<URL> urls = interfaceConfig.loadRegistries(true);
+        TestCase.assertEquals(1, urls.size());
+        URL url = urls.get(0);
+        TestCase.assertEquals("registry", url.getProtocol());
+        TestCase.assertEquals("addr1:9090", url.getAddress());
+        TestCase.assertEquals(RegistryService.class.getName(), url.getPath());
+        TestCase.assertTrue(url.getParameters().containsKey("timestamp"));
+        TestCase.assertTrue(url.getParameters().containsKey("pid"));
+        TestCase.assertTrue(url.getParameters().containsKey("registry"));
+        TestCase.assertTrue(url.getParameters().containsKey("dubbo"));
+    }
+
+    @Test
+    public void testLoadMonitor() throws Exception {
+        System.setProperty("dubbo.monitor.address", "monitor-addr:12080");
+        System.setProperty("dubbo.monitor.protocol", "monitor");
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        URL url = interfaceConfig.loadMonitor(new URL("dubbo", "addr1", 9090));
+        TestCase.assertEquals("monitor-addr:12080", url.getAddress());
+        TestCase.assertEquals(MonitorService.class.getName(), url.getParameter("interface"));
+        TestCase.assertNotNull(url.getParameter("dubbo"));
+        TestCase.assertNotNull(url.getParameter("pid"));
+        TestCase.assertNotNull(url.getParameter("timestamp"));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkInterfaceAndMethods1() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkInterfaceAndMethods(null, null);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkInterfaceAndMethods2() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkInterfaceAndMethods(AbstractInterfaceConfigTest.class, null);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkInterfaceAndMethod3() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkInterfaceAndMethods(Greeting.class, Collections.singletonList(methodConfig));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkInterfaceAndMethod4() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setName("nihao");
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkInterfaceAndMethods(Greeting.class, Collections.singletonList(methodConfig));
+    }
+
+    @Test
+    public void checkInterfaceAndMethod5() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setName("hello");
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.checkInterfaceAndMethods(Greeting.class, Collections.singletonList(methodConfig));
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock1() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLocal(GreetingLocal1.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock2() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLocal(GreetingLocal2.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test
+    public void checkStubAndMock3() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLocal(GreetingLocal3.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock4() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setStub(GreetingLocal1.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock5() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setStub(GreetingLocal2.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test
+    public void checkStubAndMock6() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setStub(GreetingLocal3.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock7() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setMock("return {a, b}");
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock8() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setMock(GreetingMock1.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test(expected = IllegalStateException.class)
+    public void checkStubAndMock9() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setMock(GreetingMock2.class.getName());
+        interfaceConfig.checkStubAndMock(Greeting.class);
+    }
+
+    @Test
+    public void testLocal() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLocal((Boolean) null);
+        TestCase.assertNull(interfaceConfig.getLocal());
+        interfaceConfig.setLocal(true);
+        TestCase.assertEquals("true", interfaceConfig.getLocal());
+        interfaceConfig.setLocal("GreetingMock");
+        TestCase.assertEquals("GreetingMock", interfaceConfig.getLocal());
+    }
+
+    @Test
+    public void testStub() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setStub((Boolean) null);
+        TestCase.assertNull(interfaceConfig.getStub());
+        interfaceConfig.setStub(true);
+        TestCase.assertEquals("true", interfaceConfig.getStub());
+        interfaceConfig.setStub("GreetingMock");
+        TestCase.assertEquals("GreetingMock", interfaceConfig.getStub());
+    }
+
+    @Test
+    public void testCluster() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setCluster("mockcluster");
+        TestCase.assertEquals("mockcluster", interfaceConfig.getCluster());
+    }
+
+    @Test
+    public void testProxy() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setProxy("mockproxyfactory");
+        TestCase.assertEquals("mockproxyfactory", interfaceConfig.getProxy());
+    }
+
+    @Test
+    public void testConnections() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setConnections(1);
+        TestCase.assertEquals(1, interfaceConfig.getConnections().intValue());
+    }
+
+    @Test
+    public void testFilter() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setFilter("mockfilter");
+        TestCase.assertEquals("mockfilter", interfaceConfig.getFilter());
+    }
+
+    @Test
+    public void testListener() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setListener("mockinvokerlistener");
+        TestCase.assertEquals("mockinvokerlistener", interfaceConfig.getListener());
+    }
+
+    @Test
+    public void testLayer() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setLayer("layer");
+        TestCase.assertEquals("layer", interfaceConfig.getLayer());
+    }
+
+    @Test
+    public void testApplication() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        ApplicationConfig applicationConfig = new ApplicationConfig();
+        interfaceConfig.setApplication(applicationConfig);
+        TestCase.assertSame(applicationConfig, interfaceConfig.getApplication());
+    }
+
+    @Test
+    public void testModule() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        ModuleConfig moduleConfig = new ModuleConfig();
+        interfaceConfig.setModule(moduleConfig);
+        TestCase.assertSame(moduleConfig, interfaceConfig.getModule());
+    }
+
+    @Test
+    public void testRegistry() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        RegistryConfig registryConfig = new RegistryConfig();
+        interfaceConfig.setRegistry(registryConfig);
+        TestCase.assertSame(registryConfig, interfaceConfig.getRegistry());
+    }
+
+    @Test
+    public void testRegistries() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        RegistryConfig registryConfig = new RegistryConfig();
+        interfaceConfig.setRegistries(Collections.singletonList(registryConfig));
+        TestCase.assertEquals(1, interfaceConfig.getRegistries().size());
+        TestCase.assertSame(registryConfig, interfaceConfig.getRegistries().get(0));
+    }
+
+    @Test
+    public void testMonitor() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setMonitor("monitor-addr");
+        TestCase.assertEquals("monitor-addr", interfaceConfig.getMonitor().getAddress());
+        MonitorConfig monitorConfig = new MonitorConfig();
+        interfaceConfig.setMonitor(monitorConfig);
+        TestCase.assertSame(monitorConfig, interfaceConfig.getMonitor());
+    }
+
+    @Test
+    public void testOwner() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setOwner("owner");
+        TestCase.assertEquals("owner", interfaceConfig.getOwner());
+    }
+
+    @Test
+    public void testCallbacks() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setCallbacks(2);
+        TestCase.assertEquals(2, interfaceConfig.getCallbacks().intValue());
+    }
+
+    @Test
+    public void testOnconnect() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setOnconnect("onConnect");
+        TestCase.assertEquals("onConnect", interfaceConfig.getOnconnect());
+    }
+
+    @Test
+    public void testOndisconnect() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setOndisconnect("onDisconnect");
+        TestCase.assertEquals("onDisconnect", interfaceConfig.getOndisconnect());
+    }
+
+    @Test
+    public void testScope() throws Exception {
+        InterfaceConfig interfaceConfig = new InterfaceConfig();
+        interfaceConfig.setScope("scope");
+        TestCase.assertEquals("scope", interfaceConfig.getScope());
+    }
+
+    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
+                }
+            }
+        }
+    }
+
+    private static class InterfaceConfig extends AbstractInterfaceConfig {
+
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java
new file mode 100644
index 0000000..41549e3
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractMethodConfigTest.java
@@ -0,0 +1,119 @@
+/*
+ * 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.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.hamcrest.Matchers.isEmptyOrNullString;
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+public class AbstractMethodConfigTest {
+    @Test
+    public void testTimeout() throws Exception {
+        MethodConfig methodConfig = new MethodConfig();
+        methodConfig.setTimeout(10);
+        assertThat(methodConfig.getTimeout(), 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-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java
new file mode 100644
index 0000000..a53217c
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractReferenceConfigTest.java
@@ -0,0 +1,157 @@
+/*
+ * 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;
+import org.junit.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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.junit.Assert.assertThat;
+
+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(Constants.REFERENCE_FILTER_KEY, "prefilter");
+        AbstractInterfaceConfig.appendParameters(parameters, referenceConfig);
+        assertThat(parameters, hasValue("prefilter,mockfilter"));
+    }
+
+    @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(Constants.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(Constants.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(Constants.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"));
+    }
+
+    private static class ReferenceConfig extends AbstractReferenceConfig {
+
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java
new file mode 100644
index 0000000..3f79541
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/AbstractServiceConfigTest.java
@@ -0,0 +1,181 @@
+/*
+ * 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;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+import static org.junit.Assert.assertThat;
+
+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.io");
+        assertThat(serviceConfig.getDocument(), equalTo("http://dubbo.io"));
+        Map<String, String> parameters = new HashMap<String, String>();
+        AbstractServiceConfig.appendParameters(parameters, serviceConfig);
+        assertThat(parameters, hasEntry("document", "http%3A%2F%2Fdubbo.io"));
+    }
+
+    @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(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(Constants.SERVICE_FILTER_KEY, "prefilter");
+        AbstractServiceConfig.appendParameters(parameters, serviceConfig);
+        assertThat(parameters, hasEntry(Constants.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(Constants.EXPORTER_LISTENER_KEY, "prelistener");
+        AbstractServiceConfig.appendParameters(parameters, serviceConfig);
+        assertThat(parameters, hasEntry(Constants.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-bootstrap/src/main/test/java/org/apache/dubbo/config/ApplicationConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ApplicationConfigTest.java
new file mode 100644
index 0000000..1cc5a22
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ApplicationConfigTest.java
@@ -0,0 +1,177 @@
+/*
+ * 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;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+import static org.junit.Assert.assertThat;
+
+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(Constants.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(expected = IllegalStateException.class)
+    public void testEnvironment2() throws Exception {
+        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(Constants.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(Constants.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(Constants.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(Constants.ACCEPT_FOREIGN_IP, "true"));
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ArgumentConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ArgumentConfigTest.java
new file mode 100644
index 0000000..26051f9
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+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-bootstrap/src/main/test/java/org/apache/dubbo/config/ConsumerConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ConsumerConfigTest.java
new file mode 100644
index 0000000..b9a1a9a
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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.Test;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+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-bootstrap/src/main/test/java/org/apache/dubbo/config/GenericServiceTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/GenericServiceTest.java
new file mode 100644
index 0000000..eed9b1e
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/GenericServiceTest.java
@@ -0,0 +1,314 @@
+/*
+ * 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;
+import org.apache.dubbo.common.beanutil.JavaBeanAccessor;
+import org.apache.dubbo.common.beanutil.JavaBeanDescriptor;
+import org.apache.dubbo.common.beanutil.JavaBeanSerializeUtil;
+import org.apache.dubbo.common.extension.ExtensionLoader;
+import org.apache.dubbo.common.serialize.Serialization;
+import org.apache.dubbo.common.utils.ReflectUtils;
+import org.apache.dubbo.config.api.DemoException;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.api.User;
+import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
+import org.apache.dubbo.rpc.service.GenericException;
+import org.apache.dubbo.rpc.service.GenericService;
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.io.ByteArrayInputStream;
+import java.io.ByteArrayOutputStream;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+import java.util.concurrent.atomic.AtomicReference;
+
+/**
+ * GenericServiceTest
+ */
+public class GenericServiceTest {
+
+    @Test
+    public void testGenericServiceException() {
+        ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();
+        service.setApplication(new ApplicationConfig("generic-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29581));
+        service.setInterface(DemoService.class.getName());
+        service.setRef(new GenericService() {
+
+            public Object $invoke(String method, String[] parameterTypes, Object[] args)
+                    throws GenericException {
+                if ("sayName".equals(method)) {
+                    return "Generic " + args[0];
+                }
+                if ("throwDemoException".equals(method)) {
+                    throw new GenericException(DemoException.class.getName(), "Generic");
+                }
+                if ("getUsers".equals(method)) {
+                    return args[0];
+                }
+                return null;
+            }
+        });
+        service.export();
+        try {
+            ReferenceConfig<DemoService> reference = new ReferenceConfig<DemoService>();
+            reference.setApplication(new ApplicationConfig("generic-consumer"));
+            reference.setInterface(DemoService.class);
+            reference.setUrl("dubbo://127.0.0.1:29581?generic=true&timeout=3000");
+            DemoService demoService = reference.get();
+            try {
+                // say name
+                Assert.assertEquals("Generic Haha", demoService.sayName("Haha"));
+                // get users
+                List<User> users = new ArrayList<User>();
+                users.add(new User("Aaa"));
+                users = demoService.getUsers(users);
+                Assert.assertEquals("Aaa", users.get(0).getName());
+                // throw demo exception
+                try {
+                    demoService.throwDemoException();
+                    Assert.fail();
+                } catch (DemoException e) {
+                    Assert.assertEquals("Generic", e.getMessage());
+                }
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+    @SuppressWarnings("unchecked")
+    @Test
+    public void testGenericReferenceException() {
+        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();
+        service.setApplication(new ApplicationConfig("generic-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29581));
+        service.setInterface(DemoService.class.getName());
+        service.setRef(new DemoServiceImpl());
+        service.export();
+        try {
+            ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
+            reference.setApplication(new ApplicationConfig("generic-consumer"));
+            reference.setInterface(DemoService.class);
+            reference.setUrl("dubbo://127.0.0.1:29581?scope=remote&timeout=3000");
+            reference.setGeneric(true);
+            GenericService genericService = reference.get();
+            try {
+                List<Map<String, Object>> users = new ArrayList<Map<String, Object>>();
+                Map<String, Object> user = new HashMap<String, Object>();
+                user.put("class", "org.apache.dubbo.config.api.User");
+                user.put("name", "actual.provider");
+                users.add(user);
+                users = (List<Map<String, Object>>) genericService.$invoke("getUsers", new String[]{List.class.getName()}, new Object[]{users});
+                Assert.assertEquals(1, users.size());
+                Assert.assertEquals("actual.provider", users.get(0).get("name"));
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+    @Test
+    public void testGenericSerializationJava() throws Exception {
+        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();
+        service.setApplication(new ApplicationConfig("generic-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29581));
+        service.setInterface(DemoService.class.getName());
+        DemoServiceImpl ref = new DemoServiceImpl();
+        service.setRef(ref);
+        service.export();
+        try {
+            ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
+            reference.setApplication(new ApplicationConfig("generic-consumer"));
+            reference.setInterface(DemoService.class);
+            reference.setUrl("dubbo://127.0.0.1:29581?scope=remote&timeout=3000");
+            reference.setGeneric(Constants.GENERIC_SERIALIZATION_NATIVE_JAVA);
+            GenericService genericService = reference.get();
+            try {
+                String name = "kimi";
+                ByteArrayOutputStream bos = new ByteArrayOutputStream(512);
+                ExtensionLoader.getExtensionLoader(Serialization.class)
+                        .getExtension("nativejava").serialize(null, bos).writeObject(name);
+                byte[] arg = bos.toByteArray();
+                Object obj = genericService.$invoke("sayName", new String[]{String.class.getName()}, new Object[]{arg});
+                Assert.assertTrue(obj instanceof byte[]);
+                byte[] result = (byte[]) obj;
+                Assert.assertEquals(ref.sayName(name), ExtensionLoader.getExtensionLoader(Serialization.class)
+                        .getExtension("nativejava").deserialize(null, new ByteArrayInputStream(result)).readObject().toString());
+
+                // getUsers
+                List<User> users = new ArrayList<User>();
+                User user = new User();
+                user.setName(name);
+                users.add(user);
+                bos = new ByteArrayOutputStream(512);
+                ExtensionLoader.getExtensionLoader(Serialization.class)
+                        .getExtension("nativejava").serialize(null, bos).writeObject(users);
+                obj = genericService.$invoke("getUsers",
+                        new String[]{List.class.getName()},
+                        new Object[]{bos.toByteArray()});
+                Assert.assertTrue(obj instanceof byte[]);
+                result = (byte[]) obj;
+                Assert.assertEquals(users,
+                        ExtensionLoader.getExtensionLoader(Serialization.class)
+                                .getExtension("nativejava")
+                                .deserialize(null, new ByteArrayInputStream(result))
+                                .readObject());
+
+                // echo(int)
+                bos = new ByteArrayOutputStream(512);
+                ExtensionLoader.getExtensionLoader(Serialization.class).getExtension("nativejava")
+                        .serialize(null, bos).writeObject(Integer.MAX_VALUE);
+                obj = genericService.$invoke("echo", new String[]{int.class.getName()}, new Object[]{bos.toByteArray()});
+                Assert.assertTrue(obj instanceof byte[]);
+                Assert.assertEquals(Integer.MAX_VALUE,
+                        ExtensionLoader.getExtensionLoader(Serialization.class)
+                                .getExtension("nativejava")
+                                .deserialize(null, new ByteArrayInputStream((byte[]) obj))
+                                .readObject());
+
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+    @Test
+    public void testGenericInvokeWithBeanSerialization() throws Exception {
+        ServiceConfig<DemoService> service = new ServiceConfig<DemoService>();
+        service.setApplication(new ApplicationConfig("bean-provider"));
+        service.setInterface(DemoService.class);
+        service.setRegistry(new RegistryConfig("N/A"));
+        DemoServiceImpl impl = new DemoServiceImpl();
+        service.setRef(impl);
+        service.setProtocol(new ProtocolConfig("dubbo", 29581));
+        service.export();
+        ReferenceConfig<GenericService> reference = null;
+        try {
+            reference = new ReferenceConfig<GenericService>();
+            reference.setApplication(new ApplicationConfig("bean-consumer"));
+            reference.setInterface(DemoService.class);
+            reference.setUrl("dubbo://127.0.0.1:29581?scope=remote&timeout=3000");
+            reference.setGeneric(Constants.GENERIC_SERIALIZATION_BEAN);
+            GenericService genericService = reference.get();
+            User user = new User();
+            user.setName("zhangsan");
+            List<User> users = new ArrayList<User>();
+            users.add(user);
+            Object result = genericService.$invoke("getUsers", new String[]{ReflectUtils.getName(List.class)}, new Object[]{JavaBeanSerializeUtil.serialize(users, JavaBeanAccessor.METHOD)});
+            Assert.assertTrue(result instanceof JavaBeanDescriptor);
+            JavaBeanDescriptor descriptor = (JavaBeanDescriptor) result;
+            Assert.assertTrue(descriptor.isCollectionType());
+            Assert.assertEquals(1, descriptor.propertySize());
+            descriptor = (JavaBeanDescriptor) descriptor.getProperty(0);
+            Assert.assertTrue(descriptor.isBeanType());
+            Assert.assertEquals(user.getName(), ((JavaBeanDescriptor) descriptor.getProperty("name")).getPrimitiveProperty());
+        } finally {
+            if (reference != null) {
+                reference.destroy();
+            }
+            service.unexport();
+        }
+    }
+
+    @Test
+    public void testGenericImplementationWithBeanSerialization() throws Exception {
+        final AtomicReference reference = new AtomicReference();
+        ServiceConfig<GenericService> service = new ServiceConfig<GenericService>();
+        service.setApplication(new ApplicationConfig("bean-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29581));
+        service.setInterface(DemoService.class.getName());
+        service.setRef(new GenericService() {
+
+            public Object $invoke(String method, String[] parameterTypes, Object[] args) throws GenericException {
+                if ("getUsers".equals(method)) {
+                    GenericParameter arg = new GenericParameter();
+                    arg.method = method;
+                    arg.parameterTypes = parameterTypes;
+                    arg.arguments = args;
+                    reference.set(arg);
+                    return args[0];
+                }
+                if ("sayName".equals(method)) {
+                    return null;
+                }
+                return args;
+            }
+        });
+        service.export();
+        ReferenceConfig<DemoService> ref = null;
+        try {
+            ref = new ReferenceConfig<DemoService>();
+            ref.setApplication(new ApplicationConfig("bean-consumer"));
+            ref.setInterface(DemoService.class);
+            ref.setUrl("dubbo://127.0.0.1:29581?scope=remote&generic=bean&timeout=3000");
+            DemoService demoService = ref.get();
+            User user = new User();
+            user.setName("zhangsan");
+            List<User> users = new ArrayList<User>();
+            users.add(user);
+            List<User> result = demoService.getUsers(users);
+            Assert.assertEquals(users.size(), result.size());
+            Assert.assertEquals(user.getName(), result.get(0).getName());
+
+            GenericParameter gp = (GenericParameter) reference.get();
+            Assert.assertEquals("getUsers", gp.method);
+            Assert.assertEquals(1, gp.parameterTypes.length);
+            Assert.assertEquals(ReflectUtils.getName(List.class), gp.parameterTypes[0]);
+            Assert.assertEquals(1, gp.arguments.length);
+            Assert.assertTrue(gp.arguments[0] instanceof JavaBeanDescriptor);
+            JavaBeanDescriptor descriptor = (JavaBeanDescriptor) gp.arguments[0];
+            Assert.assertTrue(descriptor.isCollectionType());
+            Assert.assertEquals(ArrayList.class.getName(), descriptor.getClassName());
+            Assert.assertEquals(1, descriptor.propertySize());
+            descriptor = (JavaBeanDescriptor) descriptor.getProperty(0);
+            Assert.assertTrue(descriptor.isBeanType());
+            Assert.assertEquals(User.class.getName(), descriptor.getClassName());
+            Assert.assertEquals(user.getName(), ((JavaBeanDescriptor) descriptor.getProperty("name")).getPrimitiveProperty());
+            Assert.assertNull(demoService.sayName("zhangsan"));
+        } finally {
+            if (ref != null) {
+                ref.destroy();
+            }
+            service.unexport();
+        }
+    }
+
+    protected static class GenericParameter {
+
+        String method;
+
+        String[] parameterTypes;
+
+        Object[] arguments;
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/MethodConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/MethodConfigTest.java
new file mode 100644
index 0000000..8f7e860
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/MethodConfigTest.java
@@ -0,0 +1,182 @@
+/*
+ * 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;
+import org.hamcrest.Matchers;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+import static org.junit.Assert.assertThat;
+
+public class MethodConfigTest {
+    @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) Constants.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) Constants.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) Constants.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) Constants.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) Constants.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) Constants.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-bootstrap/src/main/test/java/org/apache/dubbo/config/ModuleConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ModuleConfigTest.java
new file mode 100644
index 0000000..c535e99
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ModuleConfigTest.java
@@ -0,0 +1,110 @@
+/*
+ * 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.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+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.junit.Assert.assertThat;
+
+public class ModuleConfigTest {
+    @Test(expected = IllegalStateException.class)
+    public void testName1() throws Exception {
+        ModuleConfig module = new ModuleConfig();
+        Map<String, String> parameters = new HashMap<String, String>();
+        ModuleConfig.appendParameters(parameters, module);
+    }
+
+    @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-bootstrap/src/main/test/java/org/apache/dubbo/config/MonitorConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/MonitorConfigTest.java
new file mode 100644
index 0000000..c666072
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+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-bootstrap/src/main/test/java/org/apache/dubbo/config/ProtocolConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ProtocolConfigTest.java
new file mode 100644
index 0000000..04c5a43
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ProtocolConfigTest.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.apache.dubbo.config.mock.MockProtocol2;
+import org.apache.dubbo.rpc.Protocol;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.is;
+import static org.junit.Assert.assertThat;
+
+public class ProtocolConfigTest {
+
+    @Test
+    public void testDestroy() throws Exception {
+        Protocol protocol = Mockito.mock(Protocol.class);
+        MockProtocol2.delegate = protocol;
+        ProtocolConfig protocolConfig = new ProtocolConfig();
+        protocolConfig.setName("mockprotocol2");
+        protocolConfig.destroy();
+        Mockito.verify(protocol).destroy();
+    }
+
+    @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-bootstrap/src/main/test/java/org/apache/dubbo/config/ProviderConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ProviderConfigTest.java
new file mode 100644
index 0000000..18c630a
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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.Test;
+
+import java.util.HashMap;
+import java.util.Map;
+
+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;
+import static org.junit.Assert.assertThat;
+
+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-bootstrap/src/main/test/java/org/apache/dubbo/config/ReferenceConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
new file mode 100644
index 0000000..0b1840f
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ReferenceConfigTest.java
@@ -0,0 +1,108 @@
+/*
+ * 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;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
+import org.junit.Assert;
+import org.junit.Test;
+
+public class ReferenceConfigTest {
+
+    @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("dubbo");
+
+        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 {
+            demoService.export();
+            rc.get();
+            Assert.assertTrue(!Constants.LOCAL_PROTOCOL.equalsIgnoreCase(
+                    rc.getInvoker().getUrl().getProtocol()));
+        } finally {
+            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("dubbo");
+
+        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();
+        }
+        Assert.assertFalse(success);
+        Assert.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 {
+            sc.export();
+            demoService = rc.get();
+            success = true;
+        } catch (Exception e) {
+            e.printStackTrace();
+        }
+        Assert.assertTrue(success);
+        Assert.assertNotNull(demoService);
+
+    }
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/RegistryConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/RegistryConfigTest.java
new file mode 100644
index 0000000..75c99b1
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/RegistryConfigTest.java
@@ -0,0 +1,178 @@
+/*
+ * 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;
+import org.junit.Test;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.equalTo;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.not;
+import static org.junit.Assert.assertThat;
+
+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(Constants.SHUTDOWN_WAIT_KEY), equalTo("10"));
+        } finally {
+            System.clearProperty(Constants.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));
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ServiceConfigTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ServiceConfigTest.java
new file mode 100644
index 0000000..b0a4aef
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/ServiceConfigTest.java
@@ -0,0 +1,205 @@
+/*
+ * 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;
+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.Before;
+import org.junit.Ignore;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import java.util.Collections;
+
+import static org.apache.dubbo.common.Constants.GENERIC_SERIALIZATION_BEAN;
+import static org.apache.dubbo.common.Constants.GENERIC_SERIALIZATION_DEFAULT;
+import static org.apache.dubbo.common.Constants.GENERIC_SERIALIZATION_NATIVE_JAVA;
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.equalTo;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.Matchers.hasEntry;
+import static org.hamcrest.Matchers.hasKey;
+import static org.hamcrest.Matchers.hasSize;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+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>();
+
+
+    @Before
+    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");
+
+        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");
+    }
+
+    @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(Constants.ANYHOST_KEY, "true"));
+        assertThat(url.getParameters(), hasEntry(Constants.APPLICATION_KEY, "app"));
+        assertThat(url.getParameters(), hasKey(Constants.BIND_IP_KEY));
+        assertThat(url.getParameters(), hasKey(Constants.BIND_PORT_KEY));
+        assertThat(url.getParameters(), hasEntry(Constants.DEFAULT_KEY + "." + Constants.EXPORT_KEY, "true"));
+        assertThat(url.getParameters(), hasEntry(Constants.EXPORT_KEY, "true"));
+        assertThat(url.getParameters(), hasEntry("echo.0.callback", "false"));
+        assertThat(url.getParameters(), hasEntry(Constants.GENERIC_KEY, "false"));
+        assertThat(url.getParameters(), hasEntry(Constants.INTERFACE_KEY, DemoService.class.getName()));
+        assertThat(url.getParameters(), hasKey(Constants.METHODS_KEY));
+        assertThat(url.getParameters().get(Constants.METHODS_KEY), containsString("echo"));
+        assertThat(url.getParameters(), hasEntry(Constants.SIDE_KEY, Constants.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
+    @Ignore("cannot pass in travis")
+    public void testUnexport() throws Exception {
+        System.setProperty(Constants.SHUTDOWN_WAIT_KEY, "0");
+        try {
+            service.export();
+            service.unexport();
+            Thread.sleep(1000);
+            Mockito.verify(exporter, Mockito.atLeastOnce()).unexport();
+        } finally {
+            System.clearProperty(Constants.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(expected = IllegalStateException.class)
+    public void testInterface1() throws Exception {
+        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(expected = IllegalArgumentException.class)
+    public void testGeneric2() throws Exception {
+        ServiceConfig service = new ServiceConfig();
+        service.setGeneric("illegal");
+    }
+
+    @Test
+    public void testUniqueServiceName() throws Exception {
+        ServiceConfig<Greeting> service = new ServiceConfig<Greeting>();
+        service.setGroup("dubbo");
+        service.setInterface(Greeting.class);
+        service.setVersion("1.0.0");
+        assertThat(service.getUniqueServiceName(), equalTo("dubbo/" + Greeting.class.getName() + ":1.0.0"));
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/api/Box.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/api/Box.java
new file mode 100644
index 0000000..e63f924
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/api/DemoException.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/api/DemoException.java
new file mode 100644
index 0000000..2f32c3f
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/api/DemoService.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/api/DemoService.java
new file mode 100644
index 0000000..c5bc722
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/api/Greeting.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/api/Greeting.java
new file mode 100644
index 0000000..c2afa98
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/api/User.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/api/User.java
new file mode 100644
index 0000000..5e55cbb
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheService.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheService.java
new file mode 100644
index 0000000..7696b24
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheServiceImpl.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheServiceImpl.java
new file mode 100644
index 0000000..14e9ee7
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheTest.java
new file mode 100644
index 0000000..6c79b8e
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/cache/CacheTest.java
@@ -0,0 +1,118 @@
+/*
+ * 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 junit.framework.TestCase;
+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.Test;
+
+import java.util.Arrays;
+import java.util.HashMap;
+import java.util.Map;
+
+/**
+ * CacheTest
+ */
+public class CacheTest extends TestCase {
+
+    private void testCache(String type) throws Exception {
+        ServiceConfig<CacheService> service = new ServiceConfig<CacheService>();
+        service.setApplication(new ApplicationConfig("cache-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("injvm"));
+        service.setInterface(CacheService.class.getName());
+        service.setRef(new CacheServiceImpl());
+        service.export();
+        try {
+            ReferenceConfig<CacheService> reference = new ReferenceConfig<CacheService>();
+            reference.setApplication(new ApplicationConfig("cache-consumer"));
+            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 testCache() throws Exception {
+        testCache("lru");
+        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", new Class[]{String.class}, new String[]{"0"}, null, null);
+
+        Cache cache = cacheFactory.getCache(url, invocation);
+        assertTrue(cache instanceof ThreadLocalCache);
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoActionByAnnotation.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoActionByAnnotation.java
new file mode 100644
index 0000000..8fd477a
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoActionByAnnotation.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.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-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoActionBySetter.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoActionBySetter.java
new file mode 100644
index 0000000..0606e26
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoInterceptor.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/consumer/DemoInterceptor.java
new file mode 100644
index 0000000..46d7e9a
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java
new file mode 100644
index 0000000..7630842
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/invoker/DelegateProviderMetaDataInvokerTest.java
@@ -0,0 +1,59 @@
+/*
+ * 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.Before;
+import org.junit.Test;
+import org.mockito.Mockito;
+
+import static org.hamcrest.Matchers.sameInstance;
+import static org.junit.Assert.assertThat;
+
+public class DelegateProviderMetaDataInvokerTest {
+    private ServiceConfig service;
+    private Invoker<Greeting> invoker;
+
+    @Before
+    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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingLocal1.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingLocal1.java
new file mode 100644
index 0000000..f3d5ee5
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingLocal2.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingLocal2.java
new file mode 100644
index 0000000..8cae406
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingLocal3.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingLocal3.java
new file mode 100644
index 0000000..9b14ac6
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingMock1.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingMock1.java
new file mode 100644
index 0000000..8bfe6e6
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingMock2.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/GreetingMock2.java
new file mode 100644
index 0000000..429bff4
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockCluster.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockCluster.java
new file mode 100644
index 0000000..39bf974
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockCodec.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockCodec.java
new file mode 100644
index 0000000..c1aac42
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockDispatcher.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockDispatcher.java
new file mode 100644
index 0000000..32fffca
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockExchanger.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockExchanger.java
new file mode 100644
index 0000000..fccfd23
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockExporterListener.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockExporterListener.java
new file mode 100644
index 0000000..b93f44c
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockFilter.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockFilter.java
new file mode 100644
index 0000000..d51f123
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockInvokerListener.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockInvokerListener.java
new file mode 100644
index 0000000..c929e54
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockLoadBalance.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockLoadBalance.java
new file mode 100644
index 0000000..377f328
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProtocol.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProtocol.java
new file mode 100644
index 0000000..f4cb8ce
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProtocol.java
@@ -0,0 +1,86 @@
+/*
+ * 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;
+
+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 null;
+    }
+
+    /* (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;
+            }
+
+            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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProtocol2.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProtocol2.java
new file mode 100644
index 0000000..91653d4
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProxyFactory.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockProxyFactory.java
new file mode 100644
index 0000000..49f05d8
--- /dev/null
+++ b/dubbo-bootstrap/src/main/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;
+
+public class MockProxyFactory implements ProxyFactory {
+    @Override
+    public <T> T getProxy(Invoker<T> invoker) throws RpcException {
+        return null;
+    }
+
+    @Override
+    public <T> T getProxy(Invoker<T> invoker, boolean generic) throws RpcException {
+        return null;
+    }
+
+    @Override
+    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
+        return null;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistry.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistry.java
new file mode 100644
index 0000000..5632887
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistry.java
@@ -0,0 +1,108 @@
+/*
+ * 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.Constants;
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.NotifyListener;
+import org.apache.dubbo.registry.Registry;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * TODO Comment of MockRegistry
+ */
+public class MockRegistry implements Registry {
+
+    static URL subscribedUrl = new URL("null", "0.0.0.0", 0);
+
+    public static URL getSubscribedUrl() {
+        return subscribedUrl;
+    }
+
+    /*
+     * @see org.apache.dubbo.common.Node#getUrl()
+     */
+    public URL getUrl() {
+        return null;
+    }
+
+    /*
+     * @see org.apache.dubbo.common.Node#isAvailable()
+     */
+    @Override
+    public boolean isAvailable() {
+        return true;
+    }
+
+    /*
+     * @see org.apache.dubbo.common.Node#destroy()
+     */
+    @Override
+    public void destroy() {
+
+    }
+
+    /*
+     * @see org.apache.dubbo.registry.RegistryService#register(org.apache.dubbo.common.URL)
+     */
+    @Override
+    public void register(URL url) {
+
+    }
+
+    /*
+     * @see org.apache.dubbo.registry.RegistryService#unregister(org.apache.dubbo.common.URL)
+     */
+    @Override
+    public void unregister(URL url) {
+
+    }
+
+    /*
+     * @see org.apache.dubbo.registry.RegistryService#subscribe(org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener)
+     */
+    @Override
+    public void subscribe(URL url, NotifyListener listener) {
+        this.subscribedUrl = url;
+        List<URL> urls = new ArrayList<URL>();
+
+        urls.add(url.setProtocol("mockprotocol")
+                .removeParameter(Constants.CATEGORY_KEY)
+                .addParameter(Constants.METHODS_KEY, "sayHello"));
+
+        listener.notify(urls);
+    }
+
+    /*
+     * @see org.apache.dubbo.registry.RegistryService#unsubscribe(org.apache.dubbo.common.URL, org.apache.dubbo.registry.NotifyListener)
+     */
+    @Override
+    public void unsubscribe(URL url, NotifyListener listener) {
+
+    }
+
+    /*
+     * @see org.apache.dubbo.registry.RegistryService#lookup(org.apache.dubbo.common.URL)
+     */
+    @Override
+    public List<URL> lookup(URL url) {
+        return null;
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistryFactory.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistryFactory.java
new file mode 100644
index 0000000..1e0e6e7
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistryFactory.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.registry.Registry;
+import org.apache.dubbo.registry.RegistryFactory;
+
+/**
+ * TODO Comment of MockRegistryFactory
+ */
+public class MockRegistryFactory implements RegistryFactory {
+
+    /*
+     * @see org.apache.dubbo.registry.RegistryFactory#getRegistry(org.apache.dubbo.common.URL)
+     */
+    @Override
+    public Registry getRegistry(URL url) {
+
+        return new MockRegistry();
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistryFactory2.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistryFactory2.java
new file mode 100644
index 0000000..2ab3da8
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockRegistryFactory2.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.mock;
+
+import org.apache.dubbo.common.URL;
+import org.apache.dubbo.registry.Registry;
+import org.apache.dubbo.registry.RegistryFactory;
+
+public class MockRegistryFactory2 implements RegistryFactory {
+    public static Registry registry;
+
+    @Override
+    public Registry getRegistry(URL url) {
+        return registry;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockStatusChecker.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockStatusChecker.java
new file mode 100644
index 0000000..e144c7b
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockStatusChecker.java
@@ -0,0 +1,28 @@
+/*
+ * 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.status.Status;
+import org.apache.dubbo.common.status.StatusChecker;
+
+public class MockStatusChecker implements StatusChecker {
+    @Override
+    public Status check() {
+        return null;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockTelnetHandler.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockTelnetHandler.java
new file mode 100644
index 0000000..a08160f
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockTelnetHandler.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.remoting.Channel;
+import org.apache.dubbo.remoting.RemotingException;
+import org.apache.dubbo.remoting.telnet.TelnetHandler;
+
+public class MockTelnetHandler implements TelnetHandler {
+    @Override
+    public String telnet(Channel channel, String message) throws RemotingException {
+        return null;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockThreadPool.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockThreadPool.java
new file mode 100644
index 0000000..fe96689
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockThreadPool.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.common.URL;
+import org.apache.dubbo.common.threadpool.ThreadPool;
+
+import java.util.concurrent.Executor;
+
+public class MockThreadPool implements ThreadPool {
+    @Override
+    public Executor getExecutor(URL url) {
+        return null;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockTransporter.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockTransporter.java
new file mode 100644
index 0000000..08d005d
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/MockTransporter.java
@@ -0,0 +1,41 @@
+/*
+ * 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.Client;
+import org.apache.dubbo.remoting.RemotingException;
+import org.apache.dubbo.remoting.Server;
+import org.apache.dubbo.remoting.Transporter;
+import org.mockito.Mockito;
+
+public class MockTransporter implements Transporter {
+    private Server server = Mockito.mock(Server.class);
+    private Client client = Mockito.mock(Client.class);
+
+    @Override
+    public Server bind(URL url, ChannelHandler handler) throws RemotingException {
+        return server;
+    }
+
+    @Override
+    public Client connect(URL url, ChannelHandler handler) throws RemotingException {
+        return client;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/TestProxyFactory.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/TestProxyFactory.java
new file mode 100644
index 0000000..fe22bd1
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/mock/TestProxyFactory.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.common.URL;
+import org.apache.dubbo.rpc.Invoker;
+import org.apache.dubbo.rpc.RpcException;
+import org.apache.dubbo.rpc.proxy.jdk.JdkProxyFactory;
+
+public class TestProxyFactory extends JdkProxyFactory {
+    public static int count = 0;
+
+    @Override
+    public <T> Invoker<T> getInvoker(T proxy, Class<T> type, URL url) throws RpcException {
+        count++;
+        return super.getInvoker(proxy, type, url);
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.java
new file mode 100644
index 0000000..d81269e
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/provider/impl/DemoServiceImpl.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.provider.impl;
+
+import org.apache.dubbo.config.api.Box;
+import org.apache.dubbo.config.api.DemoException;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.api.User;
+
+import java.util.List;
+
+/**
+ * DemoServiceImpl
+ */
+public class DemoServiceImpl implements DemoService {
+
+    public String sayName(String name) {
+        return "say:" + name;
+    }
+
+    public Box getBox() {
+        return null;
+    }
+
+    public void throwDemoException() throws DemoException {
+        throw new DemoException("DemoServiceImpl");
+    }
+
+    public List<User> getUsers(List<User> users) {
+        return users;
+    }
+
+    public int echo(int i) {
+        return i;
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java
new file mode 100644
index 0000000..e2ebd63
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/ExporterSideConfigUrlTest.java
@@ -0,0 +1,98 @@
+/*
+ * 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.url;
+
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+import java.io.UnsupportedEncodingException;
+import java.net.URLDecoder;
+
+public class ExporterSideConfigUrlTest extends UrlTestBase {
+
+    private static final Logger log = LoggerFactory.getLogger(ExporterSideConfigUrlTest.class);
+
+    // ======================================================
+    //   tests start
+    // ======================================================  
+    @BeforeClass
+    public static void start() {
+    }
+
+
+    @Before
+    public void setUp() {
+        initServConf();
+    }
+
+    @After()
+    public void teardown() {
+    }
+
+    @Test
+    public void exporterMethodConfigUrlTest() {
+        verifyExporterUrlGeneration(methodConfForService, methodConfForServiceTable);
+    }
+
+    @Test
+    public void exporterServiceConfigUrlTest() {
+        verifyExporterUrlGeneration(servConf, servConfTable);
+    }
+
+    @Test
+    public void exporterProviderConfigUrlTest() {
+
+        verifyExporterUrlGeneration(provConf, provConfTable);
+    }
+
+    @Test
+    public void exporterRegistryConfigUrlTest() {
+
+        //verifyExporterUrlGeneration(regConfForService, regConfForServiceTable);
+    }
+
+
+    protected <T> void verifyExporterUrlGeneration(T config, Object[][] dataTable) {
+
+        // 1. fill corresponding config with data
+        ////////////////////////////////////////////////////////////
+        fillConfigs(config, dataTable, TESTVALUE1);
+
+        // 2. export service and get url parameter string from db
+        ////////////////////////////////////////////////////////////
+        servConf.export();
+        String paramStringFromDb = getProviderParamString();
+        try {
+            paramStringFromDb = URLDecoder.decode(paramStringFromDb, "UTF-8");
+        } catch (UnsupportedEncodingException e) {
+            // impossible
+        }
+
+
+        assertUrlStringWithLocalTable(paramStringFromDb, dataTable, config.getClass().getName(), TESTVALUE1);
+
+
+        // 4. unexport service
+        ////////////////////////////////////////////////////////////
+        servConf.unexport();
+    }
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.java
new file mode 100644
index 0000000..a7b5842
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/InvokerSideConfigUrlTest.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.url;
+
+import org.apache.dubbo.common.Constants;
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.ConsumerConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ReferenceConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.mock.MockRegistry;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Ignore;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+
+public class InvokerSideConfigUrlTest extends UrlTestBase {
+    private static final Logger log = LoggerFactory.getLogger(InvokerSideConfigUrlTest.class);
+
+    // ======================================================
+    //   invoker related data preparing
+    // ======================================================  
+    private ApplicationConfig appConfForConsumer;
+    private ApplicationConfig appConfForReference;
+    private RegistryConfig regConfForConsumer;
+    private RegistryConfig regConfForReference;
+    private MethodConfig methodConfForReference;
+    private ConsumerConfig consumerConf;
+    private ReferenceConfig<DemoService> refConf;
+
+    private Object appConfForConsumerTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+
+    private Object appConfForReferenceTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+
+    private Object regConfForConsumerTable[][] = {
+//            {"timeout", "registry.timeout", "int", 5000, 9000, "", "", "", "", ""}, 
+//            {"file", "registry.file", "string", "", "regConfForServiceTable.log", "", "", "", "", ""}, 
+//            {"wait", "registry.wait", "int", 0, 9000, "", "", "", "", ""}, 
+//            {"transport", "registry.transporter", "string", "netty", "mina", "", "", "", "", ""}, 
+            {"subscribe", "subscribe", "boolean", true, false, "", "", "", "", ""},
+            {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""},
+    };
+
+    private Object regConfForReferenceTable[][] = {
+            {"timeout", "registry.timeout", "int", 5000, 9000, "", "", "", "", ""},
+            {"file", "registry.file", "string", "", "regConfForServiceTable.log", "", "", "", "", ""},
+            {"wait", "registry.wait", "int", 0, 9000, "", "", "", "", ""},
+            {"transport", "registry.transporter", "string", "netty", "mina", "", "", "", "", ""},
+            {"subscribe", "subscribe", "boolean", true, false, "", "", "", "", ""},
+            {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""},
+    };
+
+    private Object methodConfForReferenceTable[][] = {
+            {"actives", "eatTiger.actives", "int", 0, 90, "", "", "", "", ""},
+            {"executes", "eatTiger.executes", "int", 0, 90, "", "", "", "", ""},
+            {"deprecated", "eatTiger.deprecated", "boolean", false, true, "", "", "", "", ""},
+            {"async", "eatTiger.async", "boolean", false, true, "", "", "", "", ""},
+            {"timeout", "eatTiger.timeout", "int", 0, 90, "", "", "", "", ""},
+    };
+
+    private Object refConfTable[][] = {
+//            {"version", "version", "string", "0.0.0", "1.2.3", "", "", "", "", ""}, 
+//            {"group", "group", "string", "", "HaominTest", "", "", "", "", ""}, 
+
+//            {"delay", "delay", "int", 0, 5, "", "", "", "", ""}, // not boolean 
+            {"timeout", "timeout", "int", 5000, 3000, "", "", "", "", ""},
+            {"retries", "retries", "int", 2, 5, "", "", "", "", ""},
+            {"connections", "connections", "boolean", 100, 20, "", "", "", "", ""},
+            {"loadbalance", "loadbalance", "string", "random", "roundrobin", "leastactive", "", "", ""},
+            {"async", "async", "boolean", false, true, "", "", "", "", ""},
+            //excluded = true
+//            {"generic", "generic", "boolean", false, true, "", "", "", "", ""},  
+            {"check", "check", "boolean", false, true, "", "", "", "", ""},
+            //{"local", "local", "string", "false", "HelloServiceLocal", "true", "", "", "", ""}, 
+            //{"local", "local", "string", "false", "true", "", "", "", "", ""}, 
+            //{"mock", "mock", "string", "false", "dubbo.test.HelloServiceMock", "true", "", "", "", ""}, 
+            {"mock", "mock", "string", "false", "false", "", "", "", "", ""},
+            {"proxy", "proxy", "boolean", "javassist", "jdk", "", "", "", "", ""},
+            {"client", "client", "string", "netty", "mina", "", "", "", "", ""},
+            {"client", "client", "string", "netty", "mina", "", "", "", "", ""},
+            {"owner", "owner", "string", "", "haomin,ludvik", "", "", "", "", ""},
+            {"actives", "actives", "int", 0, 30, "", "", "", "", ""},
+            {"cluster", "cluster", "string", "failover", "failfast", "failsafe", "failback", "forking", "", ""},
+            //excluded = true
+//            {"filter", "service.filter", "string", "default", "-generic", "", "", "", "", ""}, 
+            //excluded = true
+//            {"listener", "exporter.listener", "string", "default", "-deprecated", "", "", "", "", ""}, 
+            //{"", "", "", "", "", "", "", "", "", ""}, 
+    };
+
+    private Object consumerConfTable[][] = {
+            {"timeout", "default.timeout", "int", 5000, 8000, "", "", "", "", ""},
+            {"retries", "default.retries", "int", 2, 5, "", "", "", "", ""},
+            {"loadbalance", "default.loadbalance", "string", "random", "leastactive", "", "", "", "", ""},
+            {"async", "default.async", "boolean", false, true, "", "", "", "", ""},
+            {"connections", "default.connections", "int", 100, 5, "", "", "", "", ""},
+//            {"generic", "generic", "boolean", false, false, "", "", "", "", ""}, 
+            {"check", "check", "boolean", true, false, "", "", "", "", ""},
+            {"proxy", "proxy", "string", "javassist", "jdk", "javassist", "", "", "", ""},
+            {"owner", "owner", "string", "", "haomin", "", "", "", "", ""},
+            {"actives", "default.actives", "int", 0, 5, "", "", "", "", ""},
+            {"cluster", "default.cluster", "string", "failover", "forking", "", "", "", "", ""},
+            {"filter", "", "string", "", "", "", "", "", "", ""},
+            {"listener", "", "string", "", "", "", "", "", "", ""},
+//            {"", "", "", "", "", "", "", "", "", ""}, 
+    };
+
+    // ======================================================
+    //   test Start
+    // ====================================================== 
+
+    @BeforeClass
+    public static void start() {
+        //RegistryController.startRegistryIfAbsence(1);
+    }
+
+
+    @Before
+    public void setUp() {
+        initServConf();
+        initRefConf();
+    }
+
+    @After()
+    public void teardown() {
+        //RegistryServer.reloadCache();
+    }
+
+
+    @Test
+    public void consumerConfUrlTest() {
+        verifyInvokerUrlGeneration(consumerConf, consumerConfTable);
+    }
+
+    @Test
+    public void refConfUrlTest() {
+        verifyInvokerUrlGeneration(refConf, refConfTable);
+    }
+
+    @Ignore("parameter on register center will not be merged any longer with query parameter request from the consumer")
+    @Test
+    public void regConfForConsumerUrlTest() {
+        verifyInvokerUrlGeneration(regConfForConsumer, regConfForConsumerTable);
+    }
+
+    // ======================================================
+    //   private helper
+    // ====================================================== 
+    private void initRefConf() {
+
+        appConfForConsumer = new ApplicationConfig();
+        appConfForReference = new ApplicationConfig();
+        regConfForConsumer = new RegistryConfig();
+        regConfForReference = new RegistryConfig();
+        methodConfForReference = new MethodConfig();
+
+        refConf = new ReferenceConfig<DemoService>();
+        consumerConf = new ConsumerConfig();
+
+        methodConfForReference.setName("sayName");
+        regConfForReference.setAddress("127.0.0.1:9090");
+        regConfForReference.setProtocol("mockregistry");
+        appConfForReference.setName("ConfigTests");
+        refConf.setInterface("org.apache.dubbo.config.api.DemoService");
+
+        refConf.setApplication(appConfForReference);
+        consumerConf.setApplication(appConfForConsumer);
+
+        refConf.setRegistry(regConfForReference);
+        consumerConf.setRegistry(regConfForConsumer);
+
+        refConf.setConsumer(consumerConf);
+
+        refConf.setMethods(Arrays.asList(new MethodConfig[]{methodConfForReference}));
+
+        refConf.setScope(Constants.SCOPE_REMOTE);
+    }
+
+    private <T> void verifyInvokerUrlGeneration(T config, Object[][] dataTable) {
+        servConf.export();
+
+        fillConfigs(config, dataTable, TESTVALUE1);
+        refConf.get();
+
+        String subScribedUrlStr = getSubscribedUrlString();
+
+        System.out.println("url string=========:" + subScribedUrlStr);
+        String configName = config.getClass().getName();
+        int column = TESTVALUE1;
+
+        assertUrlStringWithLocalTable(subScribedUrlStr, dataTable, configName, column);
+
+        try {
+            refConf.destroy();
+        } catch (Exception e) {
+        }
+    }
+
+    private String getSubscribedUrlString() {
+        return MockRegistry.getSubscribedUrl().toString();
+    }
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/RpcConfigGetSetProxy.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/RpcConfigGetSetProxy.java
new file mode 100644
index 0000000..d883ec2
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/RpcConfigGetSetProxy.java
@@ -0,0 +1,166 @@
+/*
+ * 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.url;
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.AbstractConfig;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Method;
+
+
+public class RpcConfigGetSetProxy {
+
+    private static final String RPC_CONFIG_BASECLASS = AbstractConfig.class.getName();
+    private static final Logger log = LoggerFactory.getLogger(RpcConfigGetSetProxy.class);
+
+
+    private Object proxiee = null;
+    private Class<?> proxieeClass = null;
+    private Boolean isOk = false;
+
+    public RpcConfigGetSetProxy(Object p) {
+
+        if (p == null) {
+            return;
+        }
+
+        if (!isKindOf(p.getClass(), RPC_CONFIG_BASECLASS)) {
+            return;
+        }
+
+        proxiee = p;
+        //proxieeClass = c;
+        proxieeClass = p.getClass();
+        isOk = true;
+
+    }
+
+    public static boolean isKindOf(Class<?> c, String type) {
+
+        // get the class def for obj and type
+
+        Class<?> tClass;
+        try {
+            tClass = Class.forName(type);
+        } catch (ClassNotFoundException e) {
+            return false;
+        }
+
+        // check against type and superclasses
+        while (c != null) {
+            if (c == tClass) return true;
+            c = c.getSuperclass();
+        }
+
+        return false;
+    }
+
+    public boolean isOk() {
+        return isOk;
+    }
+
+    public Object setValue(String key, Object value) {
+
+        if (!isOk()) {
+            return null;
+        }
+
+        Method m = findSetMethod(key, value, proxieeClass);
+        return invoke(m, value);
+    }
+
+    public Object getValue(String key) {
+
+        if (!isOk()) {
+            return null;
+        }
+
+        Method m = findGetMethod(key, proxieeClass);
+        return invoke(m, null);
+    }
+
+    private Object invoke(Method m, Object value) {
+
+        if (m == null) {
+            return null;
+        }
+
+        try {
+            if (value == null) {
+                return m.invoke(proxiee, (Object[]) null);
+            } else {
+                return m.invoke(proxiee, value);
+            }
+        } catch (IllegalArgumentException e) {
+            log.error("IllegalArgumentException", e);
+            return null;
+        } catch (IllegalAccessException e) {
+            log.error("IllegalAccessException", e);
+            return null;
+        } catch (InvocationTargetException e) {
+            log.error("InvocationTargetException", e);
+            return null;
+        }
+    }
+
+    private Method findGetMethod(String key, Class<?> clazz) {
+
+        Method m = findMethod(key, null, "get", clazz);
+        if (m != null) {
+            return m;
+        }
+
+        return findMethod(key, null, "is", clazz);
+    }
+
+    private Method findSetMethod(String key, Object value, Class<?> clazz) {
+
+        return findMethod(key, value, "set", clazz);
+    }
+
+    private Method getMethod(String methodName, Object value, Class<?> clazz) {
+
+        try {
+            if (value == null) {
+                return clazz.getMethod(methodName, (Class<?>[]) null);
+            } else {
+                return clazz.getMethod(methodName, value.getClass());
+            }
+        } catch (SecurityException e) {
+            log.error("SecurityException: " + e.getMessage());
+            return null;
+        } catch (NoSuchMethodException e) {
+            log.error("NoSuchMethodException: " + e.getMessage());
+            return null;
+        }
+    }
+
+    private Method findMethod(String key, Object value, String prefix, Class<?> clazz) {
+
+        if (key.length() < 2) {
+            return null;
+        }
+
+        key = key.substring(0, 1).toUpperCase() + key.substring(1);
+        String methodName = prefix + key;
+
+        return getMethod(methodName, value, clazz);
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/UrlTestBase.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/UrlTestBase.java
new file mode 100644
index 0000000..b342685
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/url/UrlTestBase.java
@@ -0,0 +1,211 @@
+/*
+ * 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.url;
+
+
+import org.apache.dubbo.common.logger.Logger;
+import org.apache.dubbo.common.logger.LoggerFactory;
+import org.apache.dubbo.config.ApplicationConfig;
+import org.apache.dubbo.config.MethodConfig;
+import org.apache.dubbo.config.ProtocolConfig;
+import org.apache.dubbo.config.ProviderConfig;
+import org.apache.dubbo.config.RegistryConfig;
+import org.apache.dubbo.config.ServiceConfig;
+import org.apache.dubbo.config.api.DemoService;
+import org.apache.dubbo.config.provider.impl.DemoServiceImpl;
+
+import java.util.Arrays;
+
+import static junit.framework.TestCase.fail;
+
+@SuppressWarnings("unused")
+public class UrlTestBase {
+
+    // ======================================================
+    //   data column definition
+    // ======================================================
+    protected static final int KEY = 0;
+    protected static final int URL_KEY = 1;
+    protected static final int TESTVALUE1 = 4;
+    private static final Logger log = LoggerFactory.getLogger(UrlTestBase.class);
+    private static final int TYPE = 2;
+    private static final int DEFAULT = 3;
+    private static final int TESTVALUE2 = 5;
+    private static final int TESTVALUE3 = 6;
+    private static final int TESTVALUE4 = 7;
+    private static final int TESTVALUE5 = 8;
+    private static final int TESTVALUE6 = 9;
+    private static final int TESTVALUE7 = 10;
+    protected ApplicationConfig appConfForProvider;
+    protected ApplicationConfig appConfForService;
+    protected RegistryConfig regConfForProvider;
+    protected RegistryConfig regConfForService;
+    protected ProviderConfig provConf;
+    protected ProtocolConfig protoConfForProvider;
+    protected ProtocolConfig protoConfForService;
+    protected MethodConfig methodConfForService;
+    protected ServiceConfig<DemoService> servConf;
+    protected Object servConfTable[][] = {
+            {"proxy", "proxy", "string", "javassist", "jdk", "javassist", "", "", "", ""},
+            {"actives", "actives", "int", 0, 90, "", "", "", "", ""},
+            {"executes", "executes", "int", 0, 90, "", "", "", "", ""},
+            {"deprecated", "deprecated", "boolean", false, true, "", "", "", "", ""},
+            {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""},
+            {"accesslog", "accesslog", "string", "", "haominTest", "", "", "", "", ""},
+            {"document", "document", "string", "", "http://b2b-doc.alibaba-inc.com/display/RC/dubbo_devguide.htm?testquery=你好你好", "", "", "", "", ""},
+            {"weight", "weight", "int", 0, 90, "", "", "", "", ""},
+
+            //{"filter", "service.filter", "string", "", "", "", "", "", "", ""},
+            //{"listener", "listener", "string", "", "", "", "", "", "", ""},
+
+    };
+    protected Object regConfForServiceTable[][] = {
+            //            {"timeout", "registry.timeout", "int", 5000, 9000, "", "", "", "", ""},
+            //            {"file", "registry.file", "string", "", "regConfForServiceTable.log", "", "", "", "", ""},
+            //            {"wait", "registry.wait", "int", 0, 9000, "", "", "", "", ""},
+            //            {"transport", "registry.transporter", "string", "netty", "mina", "", "", "", "", ""},
+            //            {"subscribe", "subscribe", "boolean", true, false, "", "", "", "", ""},
+            {"dynamic", "dynamic", "boolean", true, false, "", "", "", "", ""},
+    };
+    protected Object provConfTable[][] = {
+            {"cluster", "default.cluster", "string", "string", "failover", "failfast", "failsafe", "", "", ""},
+            {"async", "default.async", "boolean", false, true, "", "", "", "", ""},
+            {"loadbalance", "default.loadbalance", "string", "random", "leastactive", "", "", "", "", ""},
+            {"connections", "default.connections", "int", 0, 60, "", "", "", "", ""},
+            {"retries", "default.retries", "int", 2, 60, "", "", "", "", ""},
+            {"timeout", "default.timeout", "int", 5000, 60, "", "", "", "", ""},
+            //change by fengting listener 没有缺省值
+            //{"listener", "exporter.listener", "string", "", "", "", "", "", "", ""},
+            //{"filter", "service.filter", "string", "", "", "", "", "", "", ""},
+
+    };
+    protected Object methodConfForServiceTable[][] = {
+            {"actives", "sayName.actives", "int", 0, 90, "", "", "", "", ""},
+            {"executes", "sayName.executes", "int", 0, 90, "", "", "", "", ""},
+            {"deprecated", "sayName.deprecated", "boolean", false, true, "", "", "", "", ""},
+            {"async", "sayName.async", "boolean", false, true, "", "", "", "", ""},
+            {"timeout", "sayName.timeout", "int", 0, 90, "", "", "", "", ""},
+    };
+    protected DemoService demoService = new DemoServiceImpl();
+    private Object appConfForProviderTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+    private Object appConfForServiceTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+    private Object regConfForProviderTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+    private Object protoConfForProviderTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+    private Object protoConfForServiceTable[][] = {
+            {"", "", "", "", "", "", "", "", "", ""},
+    };
+
+    // ======================================================
+    //   data table manipulation utils
+    // ====================================================== 
+    protected String genParamString(Object urlKey, Object value) {
+
+        return (String) urlKey + "=" + value.toString();
+    }
+
+    protected <T> void fillConfigs(T conf, Object[][] table, int column) {
+
+        for (Object[] row : table) {
+            fillConfig(conf, row, column);
+        }
+    }
+
+    protected <T> void fillConfig(T conf, Object[] row, int column) {
+
+        RpcConfigGetSetProxy proxy = new RpcConfigGetSetProxy(conf);
+        proxy.setValue((String) row[KEY], row[column]);
+
+    }
+
+    @SuppressWarnings("deprecation")
+    protected void initServConf() {
+
+        appConfForProvider = new ApplicationConfig();
+        appConfForService = new ApplicationConfig();
+        regConfForProvider = new RegistryConfig();
+        regConfForService = new RegistryConfig();
+        provConf = new ProviderConfig();
+        protoConfForProvider = new ProtocolConfig();
+        protoConfForService = new ProtocolConfig();
+        methodConfForService = new MethodConfig();
+        servConf = new ServiceConfig<DemoService>();
+
+        provConf.setApplication(appConfForProvider);
+        servConf.setApplication(appConfForService);
+
+        provConf.setRegistry(regConfForProvider);
+        servConf.setRegistry(regConfForService);
+
+        provConf.setProtocols(Arrays.asList(new ProtocolConfig[]{protoConfForProvider}));
+        servConf.setProtocols(Arrays.asList(new ProtocolConfig[]{protoConfForService}));
+
+        servConf.setMethods(Arrays.asList(new MethodConfig[]{methodConfForService}));
+        servConf.setProvider(provConf);
+
+        servConf.setRef(demoService);
+        servConf.setInterfaceClass(DemoService.class);
+
+        methodConfForService.setName("sayName");
+        regConfForService.setAddress("127.0.0.1:9090");
+        regConfForService.setProtocol("mockregistry");
+        appConfForService.setName("ConfigTests");
+    }
+
+    protected String getProviderParamString() {
+        return servConf.getExportedUrls().get(0).toString();
+    }
+
+    /**
+     * @param paramStringFromDb
+     * @param dataTable
+     * @param configName
+     * @param column
+     */
+    protected void assertUrlStringWithLocalTable(String paramStringFromDb,
+                                                 Object[][] dataTable, String configName, int column) {
+        final String FAILLOG_HEADER = "The following config items are not found in URLONE: ";
+
+        log.warn("Verifying service url for " + configName + "... ");
+        log.warn("Consumer url string: " + paramStringFromDb);
+
+        String failLog = FAILLOG_HEADER;
+        for (Object[] row : dataTable) {
+
+            String targetString = genParamString(row[URL_KEY], row[column]);
+
+            log.warn("Checking " + (String) row[KEY] + "for" + targetString);
+            if (paramStringFromDb.contains(targetString)) {
+                log.warn((String) row[KEY] + " --> " + targetString + " OK!");
+            } else {
+                failLog += targetString + ", ";
+            }
+        }
+
+        if (!failLog.equals(FAILLOG_HEADER)) {
+            fail(failLog);
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java
new file mode 100644
index 0000000..68df6cd
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/utils/MockReferenceConfig.java
@@ -0,0 +1,53 @@
+/*
+ * 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.utils;
+
+import org.apache.dubbo.config.ReferenceConfig;
+
+import java.util.concurrent.atomic.AtomicLong;
+
+public class MockReferenceConfig extends ReferenceConfig<String> {
+    static AtomicLong counter = new AtomicLong();
+
+    String value;
+    boolean destroyMethodRun = false;
+
+    public static void setCounter(long c) {
+        counter.set(c);
+    }
+
+    public boolean isGetMethodRun() {
+        return value != null;
+    }
+
+    public boolean isDestroyMethodRun() {
+        return destroyMethodRun;
+    }
+
+    @Override
+    public synchronized String get() {
+        if (value != null) return value;
+
+        value = "" + counter.getAndIncrement();
+        return value;
+    }
+
+    @Override
+    public synchronized void destroy() {
+        destroyMethodRun = true;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/utils/ReferenceConfigCacheTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/utils/ReferenceConfigCacheTest.java
new file mode 100644
index 0000000..8216609
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/utils/ReferenceConfigCacheTest.java
@@ -0,0 +1,114 @@
+/*
+ * 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.utils;
+
+import org.junit.Before;
+import org.junit.Test;
+
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertFalse;
+import static org.junit.Assert.assertTrue;
+
+public class ReferenceConfigCacheTest {
+    @Before
+    public void setUp() throws Exception {
+        MockReferenceConfig.setCounter(0);
+        ReferenceConfigCache.cacheHolder.clear();
+    }
+
+    @Test
+    public void testGetCacheSameReference() throws Exception {
+        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        MockReferenceConfig config = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        String value = cache.get(config);
+        assertTrue(config.isGetMethodRun());
+        assertEquals("0", value);
+
+        MockReferenceConfig configCopy = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        value = cache.get(configCopy);
+        assertFalse(configCopy.isGetMethodRun());
+        assertEquals("0", value);
+    }
+
+    @Test
+    public void testGetCacheDiffReference() throws Exception {
+        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        MockReferenceConfig config = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        String value = cache.get(config);
+        assertTrue(config.isGetMethodRun());
+        assertEquals("0", value);
+
+        MockReferenceConfig configCopy = buildMockReferenceConfig("XxxService", "group1", "1.0.0");
+        value = cache.get(configCopy);
+        assertTrue(configCopy.isGetMethodRun());
+        assertEquals("1", value);
+    }
+
+    @Test
+    public void testGetCacheDiffName() throws Exception {
+        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        MockReferenceConfig config = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        String value = cache.get(config);
+        assertTrue(config.isGetMethodRun());
+        assertEquals("0", value);
+
+        cache = ReferenceConfigCache.getCache("foo");
+        config = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        value = cache.get(config);
+        // still init for the same ReferenceConfig if the cache is different
+        assertTrue(config.isGetMethodRun());
+        assertEquals("1", value);
+    }
+
+    @Test
+    public void testDestroy() throws Exception {
+        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        MockReferenceConfig config = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        cache.get(config);
+        MockReferenceConfig configCopy = buildMockReferenceConfig("XxxService", "group1", "1.0.0");
+        cache.get(configCopy);
+        assertEquals(2, cache.cache.size());
+        cache.destroy(config);
+        assertTrue(config.isDestroyMethodRun());
+        assertEquals(1, cache.cache.size());
+        cache.destroy(configCopy);
+        assertTrue(configCopy.isDestroyMethodRun());
+        assertEquals(0, cache.cache.size());
+    }
+
+    @Test
+    public void testDestroyAll() throws Exception {
+        ReferenceConfigCache cache = ReferenceConfigCache.getCache();
+        MockReferenceConfig config = buildMockReferenceConfig("FooService", "group1", "1.0.0");
+        cache.get(config);
+        MockReferenceConfig configCopy = buildMockReferenceConfig("XxxService", "group1", "1.0.0");
+        cache.get(configCopy);
+        assertEquals(2, cache.cache.size());
+        cache.destroyAll();
+        assertTrue(config.isDestroyMethodRun());
+        assertTrue(configCopy.isDestroyMethodRun());
+        assertEquals(0, cache.cache.size());
+    }
+
+    private MockReferenceConfig buildMockReferenceConfig(String service, String group, String version) {
+        MockReferenceConfig config = new MockReferenceConfig();
+        config.setInterface(service);
+        config.setGroup(group);
+        config.setVersion(version);
+        return config;
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationParameter.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationParameter.java
new file mode 100644
index 0000000..70c4d0e
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationParameter.java
@@ -0,0 +1,106 @@
+/*
+ * 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.validation;
+
+import javax.validation.constraints.Future;
+import javax.validation.constraints.Max;
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Past;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+import java.io.Serializable;
+import java.util.Date;
+
+/**
+ * ValidationParameter
+ */
+public class ValidationParameter implements Serializable {
+
+    private static final long serialVersionUID = 7158911668568000392L;
+
+    @NotNull(groups = ValidationService.Update.class)
+    private Integer id;
+
+    @NotNull
+    @Size(min = 2, max = 20)
+    private String name;
+
+    // not allow to save null, but allow to update with null which means not update the field
+    @NotNull(groups = ValidationService.Save.class)
+    @Pattern(regexp = "^\\s*\\w+(?:\\.{0,1}[\\w-]+)*@[a-zA-Z0-9]+(?:[-.][a-zA-Z0-9]+)*\\.[a-zA-Z]+\\s*$")
+    private String email;
+
+    @Min(18)
+    @Max(100)
+    private int age;
+
+    @Past
+    private Date loginDate;
+
+    @Future
+    private Date expiryDate;
+
+    public Integer getId() {
+        return id;
+    }
+
+    public void setId(Integer id) {
+        this.id = id;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getEmail() {
+        return email;
+    }
+
+    public void setEmail(String email) {
+        this.email = email;
+    }
+
+    public int getAge() {
+        return age;
+    }
+
+    public void setAge(int age) {
+        this.age = age;
+    }
+
+    public Date getLoginDate() {
+        return loginDate;
+    }
+
+    public void setLoginDate(Date loginDate) {
+        this.loginDate = loginDate;
+    }
+
+    public Date getExpiryDate() {
+        return expiryDate;
+    }
+
+    public void setExpiryDate(Date expiryDate) {
+        this.expiryDate = expiryDate;
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationService.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationService.java
new file mode 100644
index 0000000..2efc5e0
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationService.java
@@ -0,0 +1,70 @@
+/*
+ * 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.validation;
+
+import org.apache.dubbo.validation.MethodValidated;
+
+import javax.validation.constraints.Min;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+
+/**
+ * ValidationService
+ * <p>
+ * Use service interface to distinguish validation scenario, for example: @NotNull(groups = ValidationService.class)
+ */
+public interface ValidationService {
+
+    /**
+     * The current logic will not verify 'groups = ValidationService.Save.class' if
+     * '@MethodValidated(ValidationService.Save.class)' is not present
+     *
+     * @param parameter
+     */
+    @MethodValidated(Save.class)
+    void save(ValidationParameter parameter);
+
+    void update(ValidationParameter parameter);
+
+    void delete(@Min(1) long id, @NotNull @Size(min = 2, max = 16) @Pattern(regexp = "^[a-zA-Z]+$") String operator);
+
+    /**
+     * Assume both id and email are needed to pass in, need to verify Save group and Update group.
+     *
+     * @param parameter
+     */
+    @MethodValidated({Save.class, Update.class})
+    void relatedQuery(ValidationParameter parameter);
+
+    /**
+     * annotation which has the same name with the method but has the first letter in capital
+     * used for distinguish validation scenario, for example: @NotNull(groups = ValidationService.Save.class)
+     * optional
+     */
+    @interface Save {
+    }
+
+    /**
+     * annotation which has the same name with the method but has the first letter in capital
+     * used for distinguish validation scenario, for example: @NotNull(groups = ValidationService.Update.class)
+     * optional
+     */
+    @interface Update {
+    }
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationServiceImpl.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationServiceImpl.java
new file mode 100644
index 0000000..837e7e4
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationServiceImpl.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.validation;
+
+/**
+ * ValidationServiceImpl
+ */
+public class ValidationServiceImpl implements ValidationService {
+
+    public void save(ValidationParameter parameter) {
+    }
+
+    public void update(ValidationParameter parameter) {
+    }
+
+    public void delete(long id, String operator) {
+    }
+
+    public void relatedQuery(ValidationParameter parameter) {
+
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationTest.java b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationTest.java
new file mode 100644
index 0000000..39655ae
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/java/org/apache/dubbo/config/validation/ValidationTest.java
@@ -0,0 +1,301 @@
+/*
+ * 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.validation;
+
+import org.apache.dubbo.config.ApplicationConfig;
+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.RpcException;
+import org.apache.dubbo.rpc.service.GenericException;
+import org.apache.dubbo.rpc.service.GenericService;
+import org.junit.Assert;
+import org.junit.Test;
+
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * GenericServiceTest
+ */
+public class ValidationTest {
+
+    @Test
+    public void testValidation() {
+        ServiceConfig<ValidationService> service = new ServiceConfig<ValidationService>();
+        service.setApplication(new ApplicationConfig("validation-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29582));
+        service.setInterface(ValidationService.class.getName());
+        service.setRef(new ValidationServiceImpl());
+        service.setValidation(String.valueOf(true));
+        service.export();
+        try {
+            ReferenceConfig<ValidationService> reference = new ReferenceConfig<ValidationService>();
+            reference.setApplication(new ApplicationConfig("validation-consumer"));
+            reference.setInterface(ValidationService.class);
+            reference.setUrl("dubbo://127.0.0.1:29582?scope=remote&validation=true");
+            ValidationService validationService = reference.get();
+            try {
+                // Save OK
+                ValidationParameter parameter = new ValidationParameter();
+                parameter.setName("liangfei");
+                parameter.setEmail("liangfei@liang.fei");
+                parameter.setAge(50);
+                parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
+                parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
+                validationService.save(parameter);
+
+                try {
+                    parameter = new ValidationParameter();
+                    parameter.setName("l");
+                    parameter.setEmail("liangfei@liang.fei");
+                    parameter.setAge(50);
+                    parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
+                    parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
+                    validationService.save(parameter);
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertNotNull(violations);
+                }
+
+                // verify save group, save error
+                try {
+                    parameter = new ValidationParameter();
+                    parameter.setName("liangfei");
+                    parameter.setAge(50);
+                    parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
+                    parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
+                    validationService.save(parameter);
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertNotNull(violations);
+                }
+
+                // relatedQuery error, no id and email is passed, will trigger validation exception for both Save
+                // and Update
+                try {
+                    parameter = new ValidationParameter();
+                    parameter.setName("liangfei");
+                    parameter.setAge(50);
+                    parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
+                    parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
+                    validationService.relatedQuery(parameter);
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertEquals(violations.size(), 2);
+                }
+
+                // Save Error
+                try {
+                    parameter = new ValidationParameter();
+                    validationService.save(parameter);
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertTrue(violations.size() == 3);
+                    Assert.assertNotNull(violations);
+                }
+
+                // Delete OK
+                validationService.delete(2, "abc");
+
+                // Delete Error
+                try {
+                    validationService.delete(2, "a");
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertNotNull(violations);
+                    Assert.assertEquals(1, violations.size());
+                }
+
+                // Delete Error
+                try {
+                    validationService.delete(0, "abc");
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertNotNull(violations);
+                    Assert.assertEquals(1, violations.size());
+                }
+                try {
+                    validationService.delete(2, null);
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertNotNull(violations);
+                    Assert.assertEquals(1, violations.size());
+                }
+                try {
+                    validationService.delete(0, null);
+                    Assert.fail();
+                } catch (ConstraintViolationException ve) {
+                    Set<ConstraintViolation<?>> violations = ve.getConstraintViolations();
+                    Assert.assertNotNull(violations);
+                    Assert.assertEquals(2, violations.size());
+                }
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+    @Test
+    public void testProviderValidation() {
+        ServiceConfig<ValidationService> service = new ServiceConfig<ValidationService>();
+        service.setApplication(new ApplicationConfig("validation-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29582));
+        service.setInterface(ValidationService.class.getName());
+        service.setRef(new ValidationServiceImpl());
+        service.setValidation(String.valueOf(true));
+        service.export();
+        try {
+            ReferenceConfig<ValidationService> reference = new ReferenceConfig<ValidationService>();
+            reference.setApplication(new ApplicationConfig("validation-consumer"));
+            reference.setInterface(ValidationService.class);
+            reference.setUrl("dubbo://127.0.0.1:29582");
+            ValidationService validationService = reference.get();
+            try {
+                // Save OK
+                ValidationParameter parameter = new ValidationParameter();
+                parameter.setName("liangfei");
+                parameter.setEmail("liangfei@liang.fei");
+                parameter.setAge(50);
+                parameter.setLoginDate(new Date(System.currentTimeMillis() - 1000000));
+                parameter.setExpiryDate(new Date(System.currentTimeMillis() + 1000000));
+                validationService.save(parameter);
+
+                // Save Error
+                try {
+                    parameter = new ValidationParameter();
+                    validationService.save(parameter);
+                    Assert.fail();
+                } catch (RpcException e) {
+                    Assert.assertTrue(e.getMessage().contains("ConstraintViolation"));
+                }
+
+                // Delete OK
+                validationService.delete(2, "abc");
+
+                // Delete Error
+                try {
+                    validationService.delete(0, "abc");
+                    Assert.fail();
+                } catch (RpcException e) {
+                    Assert.assertTrue(e.getMessage().contains("ConstraintViolation"));
+                }
+                try {
+                    validationService.delete(2, null);
+                    Assert.fail();
+                } catch (RpcException e) {
+                    Assert.assertTrue(e.getMessage().contains("ConstraintViolation"));
+                }
+                try {
+                    validationService.delete(0, null);
+                    Assert.fail();
+                } catch (RpcException e) {
+                    Assert.assertTrue(e.getMessage().contains("ConstraintViolation"));
+                }
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+    @Test
+    public void testGenericValidation() {
+        ServiceConfig<ValidationService> service = new ServiceConfig<ValidationService>();
+        service.setApplication(new ApplicationConfig("validation-provider"));
+        service.setRegistry(new RegistryConfig("N/A"));
+        service.setProtocol(new ProtocolConfig("dubbo", 29582));
+        service.setInterface(ValidationService.class.getName());
+        service.setRef(new ValidationServiceImpl());
+        service.setValidation(String.valueOf(true));
+        service.export();
+        try {
+            ReferenceConfig<GenericService> reference = new ReferenceConfig<GenericService>();
+            reference.setApplication(new ApplicationConfig("validation-consumer"));
+            reference.setInterface(ValidationService.class.getName());
+            reference.setUrl("dubbo://127.0.0.1:29582?scope=remote&validation=true&timeout=9000000");
+            reference.setGeneric(true);
+            GenericService validationService = reference.get();
+            try {
+                // Save OK
+                Map<String, Object> parameter = new HashMap<String, Object>();
+                parameter.put("name", "liangfei");
+                parameter.put("Email", "liangfei@liang.fei");
+                parameter.put("Age", 50);
+                parameter.put("LoginDate", new Date(System.currentTimeMillis() - 1000000));
+                parameter.put("ExpiryDate", new Date(System.currentTimeMillis() + 1000000));
+                validationService.$invoke("save", new String[]{ValidationParameter.class.getName()}, new Object[]{parameter});
+
+                // Save Error
+                try {
+                    parameter = new HashMap<String, Object>();
+                    validationService.$invoke("save", new String[]{ValidationParameter.class.getName()}, new Object[]{parameter});
+                    Assert.fail();
+                } catch (GenericException e) {
+                    Assert.assertTrue(e.getMessage().contains("Failed to validate service"));
+                }
+
+                // Delete OK
+                validationService.$invoke("delete", new String[]{long.class.getName(), String.class.getName()}, new Object[]{2, "abc"});
+
+                // Delete Error
+                try {
+                    validationService.$invoke("delete", new String[]{long.class.getName(), String.class.getName()}, new Object[]{0, "abc"});
+                    Assert.fail();
+                } catch (GenericException e) {
+                    Assert.assertTrue(e.getMessage().contains("Failed to validate service"));
+                }
+                try {
+                    validationService.$invoke("delete", new String[]{long.class.getName(), String.class.getName()}, new Object[]{2, null});
+                    Assert.fail();
+                } catch (GenericException e) {
+                    Assert.assertTrue(e.getMessage().contains("Failed to validate service"));
+                }
+                try {
+                    validationService.$invoke("delete", new String[]{long.class.getName(), String.class.getName()}, new Object[]{0, null});
+                    Assert.fail();
+                } catch (GenericException e) {
+                    Assert.assertTrue(e.getMessage().contains("Failed to validate service"));
+                }
+            } catch (GenericException e) {
+                Assert.assertTrue(e.getMessage().contains("Failed to validate service"));
+            } finally {
+                reference.destroy();
+            }
+        } finally {
+            service.unexport();
+        }
+    }
+
+}
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.common.status.StatusChecker b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.common.status.StatusChecker
new file mode 100644
index 0000000..d7d3b44
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.common.status.StatusChecker
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mockstatuschecker=org.apache.dubbo.config.mock.MockStatusChecker
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.common.threadpool.ThreadPool b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.common.threadpool.ThreadPool
new file mode 100644
index 0000000..f4f5d34
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.common.threadpool.ThreadPool
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mockthreadpool=org.apache.dubbo.config.mock.MockThreadPool
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory
new file mode 100644
index 0000000..7b8cf68
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.registry.RegistryFactory
@@ -0,0 +1,2 @@
+mockregistry=org.apache.dubbo.config.mock.MockRegistryFactory
+mockprotocol2=org.apache.dubbo.config.mock.MockRegistryFactory2
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Codec b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Codec
new file mode 100644
index 0000000..94f7668
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Codec
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mockcodec=org.apache.dubbo.config.mock.MockCodec
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Dispatcher b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Dispatcher
new file mode 100644
index 0000000..febb4f8
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Dispatcher
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mockdispatcher=org.apache.dubbo.config.mock.MockDispatcher
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Transporter b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Transporter
new file mode 100644
index 0000000..ef9ec51
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.Transporter
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mocktransporter=org.apache.dubbo.config.mock.MockTransporter
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.exchange.Exchanger b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.exchange.Exchanger
new file mode 100644
index 0000000..f8d3c3b
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.exchange.Exchanger
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mockexchanger=org.apache.dubbo.config.mock.MockExchanger
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.telnet.TelnetHandler b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.telnet.TelnetHandler
new file mode 100644
index 0000000..76dfd94
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.remoting.telnet.TelnetHandler
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+mocktelnethandler=org.apache.dubbo.config.mock.MockTelnetHandler
+
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener
new file mode 100644
index 0000000..f9c818d
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.ExporterListener
@@ -0,0 +1,18 @@
+#
+# 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.
+#
+
+mockexporterlistener=org.apache.dubbo.config.mock.MockExporterListener
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter
new file mode 100644
index 0000000..1938f96
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.Filter
@@ -0,0 +1 @@
+mockfilter=org.apache.dubbo.config.mock.MockFilter
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.InvokerListener b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.InvokerListener
new file mode 100644
index 0000000..9e6d042
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.InvokerListener
@@ -0,0 +1 @@
+mockinvokerlistener=org.apache.dubbo.config.mock.MockInvokerListener
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.Protocol b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.Protocol
new file mode 100644
index 0000000..6c04497
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.Protocol
@@ -0,0 +1,2 @@
+mockprotocol=org.apache.dubbo.config.mock.MockProtocol
+mockprotocol2=org.apache.dubbo.config.mock.MockProtocol2
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.ProxyFactory b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.ProxyFactory
new file mode 100644
index 0000000..ded1b88
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.ProxyFactory
@@ -0,0 +1,2 @@
+mockproxyfactory=org.apache.dubbo.config.mock.MockProxyFactory
+testproxyfactory=org.apache.dubbo.config.mock.TestProxyFactory
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.Cluster b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.Cluster
new file mode 100644
index 0000000..066d136
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.Cluster
@@ -0,0 +1 @@
+mockcluster=org.apache.dubbo.config.mock.MockCluster
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.LoadBalance b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.LoadBalance
new file mode 100644
index 0000000..23b5087
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/META-INF/services/org.apache.dubbo.rpc.cluster.LoadBalance
@@ -0,0 +1 @@
+mockloadbalance=org.apache.dubbo.config.mock.MockLoadBalance
\ No newline at end of file
diff --git a/dubbo-bootstrap/src/main/test/resources/log4j.xml b/dubbo-bootstrap/src/main/test/resources/log4j.xml
new file mode 100644
index 0000000..8607f5d
--- /dev/null
+++ b/dubbo-bootstrap/src/main/test/resources/log4j.xml
@@ -0,0 +1,28 @@
+<!--
+  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.
+  -->
+<!DOCTYPE log4j:configuration SYSTEM "log4j.dtd">
+<log4j:configuration xmlns:log4j="http://jakarta.apache.org/log4j/" debug="false">
+    <appender name="CONSOLE" class="org.apache.log4j.ConsoleAppender">
+        <layout class="org.apache.log4j.PatternLayout">
+            <param name="ConversionPattern" value="[%d{dd/MM/yy hh:mm:ss:sss z}] %t %5p %c{2}: %m%n"/>
+        </layout>
+    </appender>
+    <root>
+        <level value="INFO"/>
+        <appender-ref ref="CONSOLE"/>
+    </root>
+</log4j:configuration>
\ No newline at end of file