diff --git a/metadata/report/consul/report_test.go b/metadata/report/consul/report_test.go
index d51c32c4f11acffb20e96d3604676b6f5377f8e7..5d7a9a351757ca12ea47e96127c6974b12560a5c 100644
--- a/metadata/report/consul/report_test.go
+++ b/metadata/report/consul/report_test.go
@@ -16,3 +16,147 @@
  */
 
 package consul
+
+import (
+	"encoding/json"
+	"net/url"
+	"strconv"
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+import (
+	"github.com/apache/dubbo-go/common"
+	"github.com/apache/dubbo-go/common/constant"
+	"github.com/apache/dubbo-go/common/extension"
+	"github.com/apache/dubbo-go/metadata/identifier"
+	"github.com/apache/dubbo-go/metadata/report"
+	"github.com/apache/dubbo-go/remoting/consul"
+)
+
+func newProviderRegistryUrl(host string, port int) *common.URL {
+	url1 := common.NewURLWithOptions(
+		common.WithIp(host),
+		common.WithPort(strconv.Itoa(port)),
+		common.WithParams(url.Values{}),
+		common.WithParamsValue(constant.ROLE_KEY, strconv.Itoa(common.PROVIDER)),
+	)
+	return url1
+}
+
+func newBaseMetadataIdentifier(side string) *identifier.BaseMetadataIdentifier {
+	return &identifier.BaseMetadataIdentifier{
+		ServiceInterface: "org.apache.HelloWorld",
+		Version:          "1.0.0",
+		Group:            "group",
+		Side:             side,
+	}
+}
+
+func newMetadataIdentifier(side string) *identifier.MetadataIdentifier {
+	return &identifier.MetadataIdentifier{
+		Application:            "application",
+		BaseMetadataIdentifier: *newBaseMetadataIdentifier(side),
+	}
+}
+
+func newServiceMetadataIdentifier(side string) *identifier.ServiceMetadataIdentifier {
+	return &identifier.ServiceMetadataIdentifier{
+		Revision:               "1.0",
+		Protocol:               "dubbo",
+		BaseMetadataIdentifier: *newBaseMetadataIdentifier(side),
+	}
+}
+
+func newSubscribeMetadataIdentifier(side string) *identifier.SubscriberMetadataIdentifier {
+	return &identifier.SubscriberMetadataIdentifier{
+		Revision:           "1.0",
+		MetadataIdentifier: *newMetadataIdentifier(side),
+	}
+}
+
+type consulMetadataReportTestSuite struct {
+	t *testing.T
+	m report.MetadataReport
+}
+
+func newConsulMetadataReportTestSuite(t *testing.T, m report.MetadataReport) *consulMetadataReportTestSuite {
+	return &consulMetadataReportTestSuite{t: t, m: m}
+}
+
+func (suite *consulMetadataReportTestSuite) testStoreProviderMetadata() {
+	providerMi := newMetadataIdentifier("provider")
+	providerMeta := "provider"
+	err := suite.m.StoreProviderMetadata(providerMi, providerMeta)
+	assert.NoError(suite.t, err)
+}
+
+func (suite *consulMetadataReportTestSuite) testStoreConsumerMetadata() {
+	consumerMi := newMetadataIdentifier("consumer")
+	consumerMeta := "consumer"
+	err := suite.m.StoreProviderMetadata(consumerMi, consumerMeta)
+	assert.NoError(suite.t, err)
+}
+
+func (suite *consulMetadataReportTestSuite) testSaveServiceMetadata(url common.URL) {
+	serviceMi := newServiceMetadataIdentifier("provider")
+	err := suite.m.SaveServiceMetadata(serviceMi, url)
+	assert.NoError(suite.t, err)
+}
+
+func (suite *consulMetadataReportTestSuite) testRemoveServiceMetadata() {
+	serviceMi := newServiceMetadataIdentifier("provider")
+	err := suite.m.RemoveServiceMetadata(serviceMi)
+	assert.NoError(suite.t, err)
+}
+
+func (suite *consulMetadataReportTestSuite) testGetExportedURLs() {
+	serviceMi := newServiceMetadataIdentifier("provider")
+	urls := suite.m.GetExportedURLs(serviceMi)
+	assert.Equal(suite.t, 1, len(urls))
+}
+
+func (suite *consulMetadataReportTestSuite) testSaveSubscribedData(url common.URL) {
+	subscribeMi := newSubscribeMetadataIdentifier("provider")
+	urls := []string{url.String()}
+	bytes, _ := json.Marshal(urls)
+	err := suite.m.SaveSubscribedData(subscribeMi, string(bytes))
+	assert.Nil(suite.t, err)
+}
+
+func (suite *consulMetadataReportTestSuite) testGetSubscribedURLs() {
+	subscribeMi := newSubscribeMetadataIdentifier("provider")
+	urls := suite.m.GetSubscribedURLs(subscribeMi)
+	assert.Equal(suite.t, 1, len(urls))
+}
+
+func (suite *consulMetadataReportTestSuite) testGetServiceDefinition() {
+	providerMi := newMetadataIdentifier("provider")
+	providerMeta := suite.m.GetServiceDefinition(providerMi)
+	assert.Equal(suite.t, "provider", providerMeta)
+}
+
+func test1(t *testing.T) {
+	consulAgent := consul.NewConsulAgent(t, 8500)
+	defer consulAgent.Close()
+
+	url := newProviderRegistryUrl("localhost", 8500)
+	mf := extension.GetMetadataReportFactory("consul")
+	m := mf.CreateMetadataReport(url)
+
+	suite := newConsulMetadataReportTestSuite(t, m)
+	suite.testStoreProviderMetadata()
+	suite.testStoreConsumerMetadata()
+	suite.testSaveServiceMetadata(*url)
+	suite.testGetExportedURLs()
+	suite.testRemoveServiceMetadata()
+	suite.testSaveSubscribedData(*url)
+	suite.testGetServiceDefinition()
+}
+
+func TestConsulMetadataReport(t *testing.T) {
+	t.Run("test1", test1)
+}
diff --git a/metadata/report/nacos/report_test.go b/metadata/report/nacos/report_test.go
index 5a646c9a38b66f5032f8051f7e5fd9ac68159b88..971c7bfe8f4ad240701118bae75c4711c53b7893 100644
--- a/metadata/report/nacos/report_test.go
+++ b/metadata/report/nacos/report_test.go
@@ -58,8 +58,8 @@ func TestNacosMetadataReport_CRUD(t *testing.T) {
 	assert.Equal(t, 1, len(exportedUrls))
 
 	subMi := newSubscribeMetadataIdentifier()
-	urlList := []string{serviceUrl.String()}
-	bytes, _ := json.Marshal(urlList)
+	urls := []string{serviceUrl.String()}
+	bytes, _ := json.Marshal(urls)
 	err = rpt.SaveSubscribedData(subMi, string(bytes))
 	assert.Nil(t, err)
 
diff --git a/registry/consul/utils_test.go b/registry/consul/utils_test.go
index d66600b773ee78b43ac3da4edf8849d0019c744d..1ef20041391e13fc20f184aa604a5ffc9b33295f 100644
--- a/registry/consul/utils_test.go
+++ b/registry/consul/utils_test.go
@@ -19,24 +19,19 @@ package consul
 
 import (
 	"fmt"
-	"io/ioutil"
 	"net"
 	"net/url"
-	"os"
 	"strconv"
 	"sync"
 	"testing"
 )
 
-import (
-	"github.com/hashicorp/consul/agent"
-)
-
 import (
 	"github.com/apache/dubbo-go/common"
 	"github.com/apache/dubbo-go/common/constant"
 	"github.com/apache/dubbo-go/registry"
 	"github.com/apache/dubbo-go/remoting"
+	"github.com/apache/dubbo-go/remoting/consul"
 )
 
 var (
@@ -90,34 +85,6 @@ func newConsumerUrl(host string, port int, service string, protocol string) comm
 	return *url1
 }
 
-type testConsulAgent struct {
-	dataDir   string
-	testAgent *agent.TestAgent
-}
-
-func newConsulAgent(t *testing.T, port int) *testConsulAgent {
-	dataDir, _ := ioutil.TempDir("./", "agent")
-	hcl := `
-		ports { 
-			http = ` + strconv.Itoa(port) + `
-		}
-		data_dir = "` + dataDir + `"
-	`
-	testAgent := &agent.TestAgent{Name: t.Name(), DataDir: dataDir, HCL: hcl}
-	testAgent.Start(t)
-
-	consulAgent := &testConsulAgent{
-		dataDir:   dataDir,
-		testAgent: testAgent,
-	}
-	return consulAgent
-}
-
-func (consulAgent *testConsulAgent) close() {
-	consulAgent.testAgent.Shutdown()
-	os.RemoveAll(consulAgent.dataDir)
-}
-
 type testServer struct {
 	listener net.Listener
 	wg       sync.WaitGroup
@@ -184,8 +151,8 @@ func (suite *consulRegistryTestSuite) close() {
 
 // register -> subscribe -> unregister
 func test1(t *testing.T) {
-	consulAgent := newConsulAgent(t, registryPort)
-	defer consulAgent.close()
+	consulAgent := consul.NewConsulAgent(t, registryPort)
+	defer consulAgent.Close()
 
 	server := newServer(providerHost, providerPort)
 	defer server.close()
@@ -204,8 +171,8 @@ func test1(t *testing.T) {
 
 // subscribe -> register
 func test2(t *testing.T) {
-	consulAgent := newConsulAgent(t, registryPort)
-	defer consulAgent.close()
+	consulAgent := consul.NewConsulAgent(t, registryPort)
+	defer consulAgent.Close()
 
 	server := newServer(providerHost, providerPort)
 	defer server.close()
diff --git a/remoting/consul/agent.go b/remoting/consul/agent.go
new file mode 100644
index 0000000000000000000000000000000000000000..fd0694bde37b84cd59eed29e0c2ee3136f4ef51b
--- /dev/null
+++ b/remoting/consul/agent.go
@@ -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 consul
+
+import (
+	"io/ioutil"
+	"os"
+	"strconv"
+	"testing"
+)
+
+import (
+	"github.com/hashicorp/consul/agent"
+)
+
+// Consul agent, used for test, simulates
+// an embedded consul server.
+type ConsulAgent struct {
+	dataDir   string
+	testAgent *agent.TestAgent
+}
+
+func NewConsulAgent(t *testing.T, port int) *ConsulAgent {
+	dataDir, _ := ioutil.TempDir("./", "agent")
+	hcl := `
+		ports { 
+			http = ` + strconv.Itoa(port) + `
+		}
+		data_dir = "` + dataDir + `"
+	`
+	testAgent := &agent.TestAgent{Name: t.Name(), DataDir: dataDir, HCL: hcl}
+	testAgent.Start(t)
+
+	consulAgent := &ConsulAgent{
+		dataDir:   dataDir,
+		testAgent: testAgent,
+	}
+	return consulAgent
+}
+
+func (consulAgent *ConsulAgent) Close() error {
+	var err error
+
+	err = consulAgent.testAgent.Shutdown()
+	if err != nil {
+		return err
+	}
+
+	err = os.RemoveAll(consulAgent.dataDir)
+	if err != nil {
+		return err
+	}
+
+	return nil
+}
diff --git a/remoting/consul/agent_test.go b/remoting/consul/agent_test.go
new file mode 100644
index 0000000000000000000000000000000000000000..8cf0ac6cd80e517ab7bc1b52cc7774a708082d5e
--- /dev/null
+++ b/remoting/consul/agent_test.go
@@ -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 consul
+
+import (
+	"testing"
+)
+
+import (
+	"github.com/stretchr/testify/assert"
+)
+
+func TestNewConsulAgent(t *testing.T) {
+	consulAgent := NewConsulAgent(t, 8500)
+	err := consulAgent.Close()
+	assert.NoError(t, err)
+}