SCB-1400 Complement and improve unit test

Signed-off-by: MabinGo <bin.ma@huawei.com>
diff --git a/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java b/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java
index 5924444..631bf28 100755
--- a/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java
+++ b/cli/src/test/java/org/apache/servicecomb/toolkit/cli/CliTest.java
@@ -29,7 +29,7 @@
 public class CliTest {
 
   @Test
-  public void generateServiceCombCodeFromSingleContract() throws IOException {
+  public void testGenerateServiceCombCodeFromSingleContract() throws IOException {
 
     String[] programModels = new String[] {"SpringMVC", "POJO", "JAX-RS", "SpringBoot"};
     Path tempDir = Files.createTempDirectory(null);
@@ -59,36 +59,9 @@
 
     tempDir.toFile().deleteOnExit();
   }
-/*
 
   @Test
-  public void generateSpringCloudCodeFromSingleContract() throws IOException {
-
-    Path tempDir = Files.createTempDirectory(null);
-    Path tempFile = Paths.get(tempDir.toFile().getCanonicalPath() + "/SpringCloudServer");
-    String[] args = new String[] {
-        "generate",
-        "-l",
-        "spring",
-        "-i",
-        Paths.get("./src/test/resources/swagger.yaml").toFile().getCanonicalPath(),
-        "-o",
-        tempFile.toFile().getCanonicalPath(),
-        "--library",
-        "spring-cloud"
-    };
-    Assert.assertTrue(!Files.exists(tempFile));
-
-    ToolkitMain.main(args);
-    Assert.assertTrue(Files.exists(tempFile));
-    Assert.assertTrue(Files.size(tempFile) > 0);
-
-    tempDir.toFile().deleteOnExit();
-  }
-*/
-
-  @Test
-  public void generateCodeFromMultiContract() throws IOException {
+  public void testGenerateCodeFromMultiContract() throws IOException {
 
     Path tempDir = Files.createTempDirectory(null);
     Path tempFile = Paths.get(tempDir.toFile().getCanonicalPath() + "/ServiceComb");
diff --git a/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/GeneratorTest.java b/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/GeneratorTest.java
index c54bed2..600aea1 100755
--- a/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/GeneratorTest.java
+++ b/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/GeneratorTest.java
@@ -38,7 +38,7 @@
 public class GeneratorTest {
 
   @Test
-  public void generateProgrammingModels() throws IOException, URISyntaxException {
+  public void testGenerateProgrammingModels() throws IOException, URISyntaxException {
 
     generateCode("SpringMVC");
     generateCode("POJO");
@@ -62,8 +62,8 @@
     try {
       codeGenerator.generate();
     } catch (RuntimeException e) {
-      fail("Run 'generateProgrammingModels' failed while input " + programmingModel + " unexpected to catch RuntimeException: " + e
-          .getMessage());
+      fail("Run 'testGenerateProgrammingModels' failed while input " + programmingModel
+          + " unexpected to catch RuntimeException: " + e.getMessage());
     }
 
     Object internalGenerator = ReflectUtils.getProperty(codeGenerator, "generator");
@@ -77,7 +77,7 @@
   }
 
   @Test
-  public void getCodeGeneratorInstanse() {
+  public void testGetCodeGeneratorInstanse() {
 
     CodeGenerator defaultCodeGenerator = GeneratorFactory.getGenerator(CodeGenerator.class, "default");
     Assert.assertNotNull(defaultCodeGenerator);
diff --git a/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/ServiceCombCodegenTest.java b/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/ServiceCombCodegenTest.java
index 5846136..1b120bd 100755
--- a/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/ServiceCombCodegenTest.java
+++ b/codegen/src/test/java/org/apache/servicecomb/toolkit/codegen/ServiceCombCodegenTest.java
@@ -26,7 +26,7 @@
 public class ServiceCombCodegenTest {
 
   @Test
-  public void loadImpl() {
+  public void testLoadImpl() {
     CodegenConfig codegenConfig = CodegenConfigLoader.forName("ServiceComb");
     Assert.assertEquals(ServiceCombCodegen.class, codegenConfig.getClass());
   }
diff --git a/common/src/test/java/org/apache/servicecomb/toolkit/common/FileUtilsTest.java b/common/src/test/java/org/apache/servicecomb/toolkit/common/FileUtilsTest.java
index 2a16016..56a9bd5 100755
--- a/common/src/test/java/org/apache/servicecomb/toolkit/common/FileUtilsTest.java
+++ b/common/src/test/java/org/apache/servicecomb/toolkit/common/FileUtilsTest.java
@@ -20,6 +20,7 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
 
 import java.io.IOException;
@@ -32,12 +33,6 @@
 
   @Test
   public void createDirectoryTest() {
-    try {
-      FileUtils.createDirectory(null);
-    } catch (IOException e) {
-      assertEquals("Path is null", e.getMessage());
-    }
-
     Path path;
     try {
       path = Files.createTempDirectory("");
@@ -45,20 +40,37 @@
     } catch (IOException e) {
       fail("Run 'createDirectoryTest' failed and unexpected to catch IOException: " + e.getMessage());
     }
+
+    try {
+      FileUtils.createDirectory(null);
+    } catch (IOException e) {
+      assertEquals("Path is null", e.getMessage());
+      return;
+    }
+
+    fail("Run 'createDirectoryTest' failed, expected to catch IOException but not");
   }
 
   @Test
   public void getFilesGroupByFilenameTest() {
+    boolean succeed = false;
+
     try {
+      succeed = false;
       FileUtils.getFilesGroupByFilename(null);
     } catch (IOException e) {
       assertEquals("Path is null", e.getMessage());
+      succeed = true;
     }
+    assertTrue(succeed);
 
     try {
       FileUtils.getFilesGroupByFilename("");
     } catch (IOException e) {
       assertThat(e.getMessage(), containsString("is not exists"));
+      return;
     }
+
+    fail("Run 'getFilesGroupByFilenameTest' failed, expected to catch IOException but not");
   }
 }
\ No newline at end of file
diff --git a/common/src/test/java/org/apache/servicecomb/toolkit/common/TextCompareTest.java b/common/src/test/java/org/apache/servicecomb/toolkit/common/TextCompareTest.java
index 564adc0..9e46cd7 100755
--- a/common/src/test/java/org/apache/servicecomb/toolkit/common/TextCompareTest.java
+++ b/common/src/test/java/org/apache/servicecomb/toolkit/common/TextCompareTest.java
@@ -43,7 +43,7 @@
   Path destPath = Paths.get("./src/test/resources/compare/HelloEndPoint2.yaml");
 
   @Test
-  public void contractCompareText() throws IOException {
+  public void testContractCompareText() throws IOException {
     ContractComparator contractComparator = new ContractComparator(new String(Files.readAllBytes(sourcePath)),
         new String(Files.readAllBytes(destPath)));
     assertEquals(MyersAlgorithm.class, contractComparator.getAlgorithm().getClass());
@@ -54,7 +54,7 @@
   }
 
   @Test
-  public void contractCompareResultPrint() throws IOException {
+  public void testContractCompareResultPrint() throws IOException {
     ContractComparator contractComparator = new ContractComparator(new String(Files.readAllBytes(sourcePath)),
         new String(Files.readAllBytes(destPath)));
     assertEquals(MyersAlgorithm.class, contractComparator.getAlgorithm().getClass());
@@ -66,7 +66,7 @@
   }
 
   @Test
-  public void contractCompareAnotherAlgorithm() throws IOException {
+  public void testContractCompareAnotherAlgorithm() throws IOException {
 
     CompareAlgorithm oneLineAlgorithm = mock(CompareAlgorithm.class);
     when(oneLineAlgorithm.compare(anyString(), anyString())).then(new Answer<Object>() {
@@ -117,7 +117,7 @@
   }
 
   @Test
-  public void contractCompareException() throws IOException {
+  public void testContractCompareException() throws IOException {
 
     try (ByteArrayOutputStream bout = new ByteArrayOutputStream()) {
 
diff --git a/contractgen/src/main/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGenerator.java b/contractgen/src/main/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGenerator.java
index bdfacb8..82b2970 100755
--- a/contractgen/src/main/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGenerator.java
+++ b/contractgen/src/main/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGenerator.java
@@ -73,7 +73,6 @@
 
     Object classpathUrlsObj = config.get("classpathUrls");
     if (classpathUrlsObj instanceof List) {
-      //noinspection unchecked
       classpathUrls = (List<String>) classpathUrlsObj;
     }
 
diff --git a/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/ContractTestUtil.java b/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/ContractTestUtil.java
new file mode 100644
index 0000000..9a42f87
--- /dev/null
+++ b/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/ContractTestUtil.java
@@ -0,0 +1,50 @@
+/*
+ * 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.servicecomb.toolkit.contractgen;
+
+import javassist.ClassPool;
+import javassist.CtClass;
+import javassist.bytecode.AnnotationsAttribute;
+import javassist.bytecode.ConstPool;
+import javassist.bytecode.annotation.Annotation;
+
+public class ContractTestUtil {
+
+  public CtClass createCtClass(String className) throws Exception {
+
+    ClassPool pool = ClassPool.getDefault();
+
+    return pool.makeClass("org.apache.servicecomb.toolkit.contractgen.test." + className);
+  }
+
+  public Class putAnnotationToClass(String className, Class annotationClass) throws Exception {
+
+    CtClass ctClass = createCtClass(className);
+
+    ConstPool constPool = ctClass.getClassFile().getConstPool();
+
+    AnnotationsAttribute requestMappingAnnotationAttr = new AnnotationsAttribute(constPool,
+        AnnotationsAttribute.visibleTag);
+    Annotation requestMapping = new Annotation(annotationClass.getName(), constPool);
+
+    requestMappingAnnotationAttr.addAnnotation(requestMapping);
+    ctClass.getClassFile().addAttribute(requestMappingAnnotationAttr);
+
+    return ctClass.toClass();
+  }
+}
diff --git a/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGeneratorTest.java b/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGeneratorTest.java
index 0d48468..f282851 100644
--- a/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGeneratorTest.java
+++ b/contractgen/src/test/java/org/apache/servicecomb/toolkit/contractgen/DefaultContractsGeneratorTest.java
@@ -38,11 +38,17 @@
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 import org.apache.maven.plugin.testing.resources.TestResources;
 import org.apache.maven.project.MavenProject;
+import org.apache.servicecomb.provider.pojo.RpcSchema;
+import org.apache.servicecomb.provider.rest.common.RestSchema;
 import org.apache.servicecomb.toolkit.ContractsGenerator;
 import org.apache.servicecomb.toolkit.GeneratorFactory;
 import org.apache.servicecomb.toolkit.common.ClassMaker;
 import org.junit.Rule;
 import org.junit.Test;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import javassist.CtClass;
 
 public class DefaultContractsGeneratorTest {
 
@@ -115,12 +121,30 @@
   }
 
   @Test
-  public void testPrivateCanProcess() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
+  public void testPrivateCanProcess() throws Exception {
     DefaultContractsGenerator defaultContractsGenerator = new DefaultContractsGenerator();
     Method method = defaultContractsGenerator.getClass().getDeclaredMethod("canProcess", new Class[] {Class.class});
     method.setAccessible(true);
 
     assertFalse((boolean) method.invoke(defaultContractsGenerator, new Object[] {null}));
+
+    Class mockClass;
+    ContractTestUtil contractTestUtil = new ContractTestUtil();
+
+    CtClass ctClass = contractTestUtil.createCtClass("TestCanProcess");
+    assertFalse((boolean) method.invoke("TestCanProcess", ctClass.toClass()));
+
+    mockClass = contractTestUtil.putAnnotationToClass("TestRestSchema", RestSchema.class);
+    assertTrue((boolean) method.invoke("TestRestSchema", mockClass));
+
+    mockClass = contractTestUtil.putAnnotationToClass("TestRestController", RestController.class);
+    assertTrue((boolean) method.invoke("TestRestController", mockClass));
+
+    mockClass = contractTestUtil.putAnnotationToClass("TestRpcSchema", RpcSchema.class);
+    assertTrue((boolean) method.invoke("TestRpcSchema", mockClass));
+
+    mockClass = contractTestUtil.putAnnotationToClass("TestRequestMapping", RequestMapping.class);
+    assertTrue((boolean) method.invoke("TestRequestMapping", mockClass));
   }
 
   @Test
@@ -134,11 +158,14 @@
       method.invoke(defaultContractsGenerator, new Object[] {null});
     } catch (Exception e) {
       assertTrue(true);
+      return;
     }
+
+    fail("Run 'testgetAllClass' failed, expected to catch Exception but not");
   }
 
   @Test
-  public void getContractsGeneratorInstance() {
+  public void testGetContractsGeneratorInstance() {
 
     ContractsGenerator defaultGenerator = GeneratorFactory.getGenerator(ContractsGenerator.class, "default");
     assertNotNull(defaultGenerator);
diff --git a/docgen/src/test/java/org/apache/servicecomb/toolkit/docgen/ContractsSwaggerUIGeneratorTest.java b/docgen/src/test/java/org/apache/servicecomb/toolkit/docgen/ContractsSwaggerUIGeneratorTest.java
index 02e4843..46238be 100644
--- a/docgen/src/test/java/org/apache/servicecomb/toolkit/docgen/ContractsSwaggerUIGeneratorTest.java
+++ b/docgen/src/test/java/org/apache/servicecomb/toolkit/docgen/ContractsSwaggerUIGeneratorTest.java
@@ -39,7 +39,7 @@
 public class ContractsSwaggerUIGeneratorTest {
 
   @Test
-  public void contractTransferToSwaggerUI() throws IOException {
+  public void testContractTransferToSwaggerUI() throws IOException {
 
     Swagger20Parser swagger20Parser = new Swagger20Parser();
 
@@ -69,7 +69,7 @@
   }
 
   @Test
-  public void contractTransferToOther() {
+  public void testContractTransferToOther() {
 
     DocGenerator docGenerator = GeneratorFactory.getGenerator(DocGenerator.class, "other");
     Assert.assertNull(docGenerator);
diff --git a/toolkit-maven-plugin/pom.xml b/toolkit-maven-plugin/pom.xml
index e7b480f..e406a9e 100755
--- a/toolkit-maven-plugin/pom.xml
+++ b/toolkit-maven-plugin/pom.xml
@@ -103,9 +103,16 @@
     </dependency>
 
     <dependency>
-      <groupId>org.mockito</groupId>
-      <artifactId>mockito-core</artifactId>
-      <version>2.25.0</version>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-module-junit4</artifactId>
+      <version>1.6.2</version>
+      <scope>test</scope>
+    </dependency>
+
+    <dependency>
+      <groupId>org.powermock</groupId>
+      <artifactId>powermock-api-mockito</artifactId>
+      <version>1.6.2</version>
       <scope>test</scope>
     </dependency>
   </dependencies>
diff --git a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateMojo.java b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateMojo.java
index 222166b..c41b0c3 100755
--- a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateMojo.java
+++ b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/GenerateMojo.java
@@ -70,7 +70,7 @@
         try {
           FileUtils.createDirectory(contractOutput);
         } catch (IOException e) {
-          throw new RuntimeException("Failed to generate contract.", e);
+          throw new RuntimeException("Failed to generate contract", e);
         }
 
         GenerateUtil.generateContract(project, contractOutput, contractFileType, "default");
@@ -103,7 +103,7 @@
       try {
         FileUtils.createDirectory(codeOutput);
         GenerateUtil.generateCode(service, contractLocation, codeOutput, "default");
-      } catch (IOException e) {
+      } catch (RuntimeException | IOException e) {
         throw new RuntimeException("Failed to generate code", e);
       }
     }
@@ -113,7 +113,7 @@
     try {
       FileUtils.createDirectory(documentOutput);
       GenerateUtil.generateDocument(contractLocation, documentOutput, "default");
-    } catch (IOException e) {
+    } catch (RuntimeException | IOException e) {
       throw new RuntimeException("Failed to generate document", e);
     }
   }
diff --git a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/VerifyMojo.java b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/VerifyMojo.java
index cf7c493..ea2bdc0 100755
--- a/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/VerifyMojo.java
+++ b/toolkit-maven-plugin/src/main/java/org/apache/servicecomb/toolkit/plugin/VerifyMojo.java
@@ -61,9 +61,9 @@
       case CODE:
         try {
           sourceContractPath = FileUtils.createTempDirectory("target/tmp-contract").toFile().getCanonicalPath();
-          GenerateUtil.generateContract(project, sourceContractPath, contractFileType,"default");
-        } catch (IOException e) {
-          throw new RuntimeException("Failed to generate contract from code.", e);
+          GenerateUtil.generateContract(project, sourceContractPath, contractFileType, "default");
+        } catch (RuntimeException | IOException e) {
+          throw new RuntimeException("Failed to generate contract from code", e);
         }
 
         break;
@@ -93,7 +93,7 @@
         }
       });
     } catch (IOException e) {
-      throw new RuntimeException("Failed to verify contract", e);
+      throw new RuntimeException("Failed to verify contract ", e);
     }
   }
 }
diff --git a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateMojoTest.java b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateMojoTest.java
index 656dbf6..3f2d6df 100755
--- a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateMojoTest.java
+++ b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateMojoTest.java
@@ -20,7 +20,6 @@
 import static org.hamcrest.CoreMatchers.containsString;
 import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.assertNotEquals;
-import static org.junit.Assert.assertNotNull;
 import static org.junit.Assert.assertThat;
 import static org.junit.Assert.assertTrue;
 import static org.junit.Assert.fail;
@@ -28,16 +27,12 @@
 import static org.mockito.Mockito.mock;
 
 import java.io.File;
-import java.util.ArrayList;
-import java.util.List;
 import java.util.Objects;
 
-import org.apache.maven.plugin.AbstractMojo;
 import org.apache.maven.plugin.MojoFailureException;
 import org.apache.maven.plugin.testing.MojoRule;
 import org.apache.maven.plugin.testing.resources.TestResources;
 import org.apache.maven.project.MavenProject;
-import org.apache.servicecomb.toolkit.common.ClassMaker;
 import org.apache.servicecomb.toolkit.common.FileUtils;
 import org.junit.Rule;
 import org.junit.Test;
@@ -45,14 +40,6 @@
 
 public class GenerateMojoTest {
 
-  private static final String PLUGIN_GOAL = "generate";
-
-  private static final String TEST_PROJECT_WITHCONTRACT = "demo-with-contract";
-
-  private static final String TEST_PROJECT_WITHOUTCONTRACT = "demo-without-contract";
-
-  static final String TEST_PROJECT_CONTRACTLOCATION = "contract";
-
   @Rule
   public MojoRule rule = new MojoRule();
 
@@ -61,70 +48,57 @@
 
   @Test
   public void testGenerateMojo() throws Exception {
-    File baseDirWithContract = this.resources.getBasedir(TEST_PROJECT_WITHCONTRACT);
-    File baseDirWithoutContract = this.resources.getBasedir(TEST_PROJECT_WITHOUTCONTRACT);
-    File contractLocation = this.resources.getBasedir(TEST_PROJECT_CONTRACTLOCATION);
 
-    File pom = new File(baseDirWithContract, "pom.xml");
-    AbstractMojo generateMojo = (AbstractMojo) this.rule.lookupMojo(PLUGIN_GOAL, pom);
-    assertNotNull(generateMojo);
+    TestResourcesEx testResourcesEx = new TestResourcesEx(resources);
 
-    String testDirWithContract = baseDirWithContract + File.separator;
-    String testDirWithoutContract = baseDirWithoutContract + File.separator;
-    String classesPath = "target/classes";
-
-    final MavenProject project = mock(MavenProject.class);
-
-    // code has no contract
-    ClassMaker.compile(testDirWithoutContract);
-
-    List<String> runtimeUrlPath = new ArrayList<>();
-    runtimeUrlPath.add(testDirWithoutContract + classesPath);
-    given(project.getRuntimeClasspathElements()).willReturn(runtimeUrlPath);
-    rule.setVariableValueToObject(generateMojo, "project", project);
+    String testDirWithContract = testResourcesEx.getBasedirWithContract();
+    String testDirWithoutContract = testResourcesEx.getBasedirWithoutContract();
 
     String outputDirectory = null;
     String contractOutput = null;
     String projectOutput = null;
     String documentOutput = null;
 
+    boolean succeed;
+
+    final MavenProject project = mock(MavenProject.class);
+
+    // code has no contract
+    testResourcesEx.createMojo(rule, testResourcesEx.getBasedirWithoutContract(), "generate");
+    testResourcesEx.setVariableValueToObject("project", project);
+    given(project.getRuntimeClasspathElements()).willReturn(testResourcesEx.getRuntimeUrlPath(testDirWithoutContract));
     try {
-      outputDirectory = "./target";
+      outputDirectory = "target";
 
-      rule.setVariableValueToObject(generateMojo, "sourceType", "code");
-      rule.setVariableValueToObject(generateMojo, "outputDirectory", outputDirectory);
+      testResourcesEx.setVariableValueToObject("sourceType", "code");
+      testResourcesEx.setVariableValueToObject("outputDirectory", outputDirectory);
 
-      generateMojo.execute();
+      testResourcesEx.execute();
 
-      assertEquals(0, Objects.requireNonNull(
-          new File(rule.getVariableValueFromObject(generateMojo, "contractLocation").toString()).listFiles()).length);
+      assertEquals(0, Objects
+          .requireNonNull(new File(testResourcesEx.getVariableValueFromObject("contractLocation")).listFiles()).length);
     } catch (MojoFailureException e) {
       fail("Run 'testGenerateMojo' failed and unexpected to catch MojoFailureException: " + e.getMessage());
     }
 
     // code has contract
-    ClassMaker.compile(testDirWithContract);
-
-    runtimeUrlPath.remove(0);
-    runtimeUrlPath.add(testDirWithContract + classesPath);
-    given(project.getRuntimeClasspathElements()).willReturn(runtimeUrlPath);
-    rule.setVariableValueToObject(generateMojo, "project", project);
-
+    testResourcesEx.createMojo(rule, testResourcesEx.getBasedirWithContract(), "generate");
+    testResourcesEx.setVariableValueToObject("project", project);
+    given(project.getRuntimeClasspathElements()).willReturn(testResourcesEx.getRuntimeUrlPath(testDirWithContract));
     try {
-      outputDirectory = "./target";
+      outputDirectory = "target";
       contractOutput = outputDirectory + File.separator + "contract";
       projectOutput = outputDirectory + File.separator + "project";
       documentOutput = outputDirectory + File.separator + "document";
 
-      rule.setVariableValueToObject(generateMojo, "sourceType", "code");
-      rule.setVariableValueToObject(generateMojo, "outputDirectory", outputDirectory);
-      rule.setVariableValueToObject(generateMojo, "contractFileType", "yaml");
-      rule.setVariableValueToObject(generateMojo, "documentType", "html");
-      rule.setVariableValueToObject(generateMojo, "service", new ServiceConfig());
+      testResourcesEx.setVariableValueToObject("sourceType", "code");
+      testResourcesEx.setVariableValueToObject("outputDirectory", outputDirectory);
+      testResourcesEx.setVariableValueToObject("contractFileType", "yaml");
+      testResourcesEx.setVariableValueToObject("documentType", "html");
+      testResourcesEx.setVariableValueToObject("service", new ServiceConfig());
 
-      generateMojo.execute();
+      testResourcesEx.execute();
 
-      assertNotEquals(0, Objects.requireNonNull(new File(outputDirectory).listFiles()).length);
       assertNotEquals(0, Objects.requireNonNull(new File(contractOutput).listFiles()).length);
       assertNotEquals(0, Objects.requireNonNull(new File(projectOutput).listFiles()).length);
       assertNotEquals(0, Objects.requireNonNull(new File(documentOutput).listFiles()).length);
@@ -132,48 +106,65 @@
       fail("Run 'testGenerateMojo' failed and unexpected to catch RuntimeException: " + e.getMessage());
     }
 
-    boolean isSuccessful;
     try {
-      isSuccessful = false;
+      succeed = false;
 
-      rule.setVariableValueToObject(generateMojo, "sourceType", "contract");
-      rule.setVariableValueToObject(generateMojo, "contractLocation", null);
+      testResourcesEx.setVariableValueToObject("sourceType", "contract");
+      testResourcesEx.setVariableValueToObject("contractLocation", null);
 
-      generateMojo.execute();
+      testResourcesEx.execute();
     } catch (RuntimeException e) {
       assertEquals("Invalid or not config contract location", e.getMessage());
-      isSuccessful = true;
+      succeed = true;
     }
-    assertTrue(isSuccessful);
+    assertTrue(succeed);
 
     try {
-      isSuccessful = false;
+      succeed = false;
 
-      rule.setVariableValueToObject(generateMojo, "sourceType", "contract");
-      rule.setVariableValueToObject(generateMojo, "contractLocation", "");
+      testResourcesEx.setVariableValueToObject("sourceType", "contract");
+      testResourcesEx.setVariableValueToObject("contractLocation", "");
 
-      generateMojo.execute();
+      testResourcesEx.execute();
     } catch (RuntimeException e) {
       assertThat(e.getMessage(), containsString("is not exists"));
-      isSuccessful = true;
+      succeed = true;
     }
-    assertTrue(isSuccessful);
+    assertTrue(succeed);
 
-    outputDirectory = "./target";
+    try {
+      outputDirectory = "target";
+      projectOutput = outputDirectory + File.separator + "project";
+      documentOutput = outputDirectory + File.separator + "document";
+
+      testResourcesEx.setVariableValueToObject("sourceType", "contract");
+      testResourcesEx.setVariableValueToObject("contractLocation", testResourcesEx.getContractLocation());
+      testResourcesEx.setVariableValueToObject("outputDirectory", outputDirectory);
+      testResourcesEx.setVariableValueToObject("service", new ServiceConfig());
+
+      testResourcesEx.execute();
+
+      assertNotEquals(0, Objects.requireNonNull(new File(projectOutput).listFiles()).length);
+      assertNotEquals(0, Objects.requireNonNull(new File(documentOutput).listFiles()).length);
+    } catch (RuntimeException e) {
+      fail("Run 'testGenerateMojo' failed and unexpected to catch RuntimeException: " + e.getMessage());
+    }
+
+    outputDirectory = "target";
     projectOutput = outputDirectory + File.separator + "project";
     ServiceConfig service = new ServiceConfig();
 
-    rule.setVariableValueToObject(generateMojo, "sourceType", "code");
-    rule.setVariableValueToObject(generateMojo, "outputDirectory", outputDirectory);
+    testResourcesEx.setVariableValueToObject("sourceType", "code");
+    testResourcesEx.setVariableValueToObject("outputDirectory", outputDirectory);
     FileUtils.createDirectory(projectOutput);
-    rule.setVariableValueToObject(generateMojo, "service", null);
-    generateMojo.execute();
+    testResourcesEx.setVariableValueToObject("service", null);
+    testResourcesEx.execute();
     assertEquals(0, Objects.requireNonNull(new File(projectOutput).listFiles()).length);
 
-    rule.setVariableValueToObject(generateMojo, "sourceType", "code");
-    rule.setVariableValueToObject(generateMojo, "outputDirectory", outputDirectory);
-    rule.setVariableValueToObject(generateMojo, "service", service);
-    generateMojo.execute();
+    testResourcesEx.setVariableValueToObject("sourceType", "code");
+    testResourcesEx.setVariableValueToObject("outputDirectory", outputDirectory);
+    testResourcesEx.setVariableValueToObject("service", service);
+    testResourcesEx.execute();
     assertNotEquals(0, Objects.requireNonNull(new File(projectOutput).listFiles()).length);
   }
 }
\ No newline at end of file
diff --git a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateUtilTest.java b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateUtilTest.java
index 0fa4ef1..e485f70 100755
--- a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateUtilTest.java
+++ b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/GenerateUtilTest.java
@@ -27,25 +27,26 @@
 import static org.mockito.Mockito.when;
 
 import java.io.File;
-import java.io.IOException;
 import java.util.Objects;
 
 import org.apache.maven.artifact.DependencyResolutionRequiredException;
 import org.apache.maven.plugin.testing.resources.TestResources;
 import org.apache.maven.project.MavenProject;
+import org.junit.Before;
 import org.junit.Rule;
 import org.junit.Test;
 
 public class GenerateUtilTest {
 
-  private static final String TEST_PROJECT_CONTRACTLOCATION = "contract";
-
   @Rule
   public TestResources resources = new TestResources();
 
-  public GenerateUtilTest() throws IOException {
-  }
+  TestResourcesEx testResourcesEx;
 
+  @Before
+  public void setUp() throws Exception {
+    this.testResourcesEx = new TestResourcesEx(resources);
+  }
 
   @Test
   public void testGenerateContract() throws DependencyResolutionRequiredException {
@@ -53,6 +54,7 @@
     MavenProject project = mock(MavenProject.class);
 
     String contractOutput = "target/contract";
+    //noinspection unchecked
     when(project.getRuntimeClasspathElements()).thenThrow(DependencyResolutionRequiredException.class);
     try {
       generateContract(project, contractOutput, "yaml", "default");
@@ -65,16 +67,17 @@
   }
 
   @Test
-  public void testGenerateCode() throws IOException {
-    File contractLocation = resources.getBasedir(TEST_PROJECT_CONTRACTLOCATION);
+  public void testGenerateCode() throws Exception {
+
+    String contractLocation = this.testResourcesEx.getContractLocation();
 
     String projectOutput = "./target/project";
     ServiceConfig service = new ServiceConfig();
-    generateCode(service, contractLocation.getCanonicalPath(), projectOutput, "default");
+    generateCode(service, contractLocation, projectOutput, "default");
     assertNotEquals(0, Objects.requireNonNull(new File(projectOutput).listFiles()).length);
 
     try {
-      generateCode(service, contractLocation.getCanonicalPath(), projectOutput, "invalidType");
+      generateCode(service, contractLocation, projectOutput, "invalidType");
     } catch (RuntimeException e) {
       assertEquals("Cannot found code generator's implementation", e.getMessage());
       return;
@@ -84,15 +87,16 @@
   }
 
   @Test
-  public void testGenerateDocument() throws IOException {
-    File contractLocation = resources.getBasedir(TEST_PROJECT_CONTRACTLOCATION);
+  public void testGenerateDocument() throws Exception {
+
+    String contractLocation = this.testResourcesEx.getContractLocation();
 
     String codeOutput = "./target/document";
-    generateDocument(contractLocation.getCanonicalPath(), codeOutput, "default");
+    generateDocument(contractLocation, codeOutput, "default");
     assertNotEquals(0, Objects.requireNonNull(new File(codeOutput).listFiles()).length);
 
     try {
-      generateDocument(contractLocation.getCanonicalPath(), codeOutput, "invalidType");
+      generateDocument(contractLocation, codeOutput, "invalidType");
     } catch (RuntimeException e) {
       assertEquals("Cannot found document generator's implementation", e.getMessage());
       return;
diff --git a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/InvokeStaticMethodTest.java b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/InvokeStaticMethodTest.java
new file mode 100755
index 0000000..3ca5723
--- /dev/null
+++ b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/InvokeStaticMethodTest.java
@@ -0,0 +1,216 @@
+/*
+ * 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.servicecomb.toolkit.plugin;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Matchers.anyObject;
+import static org.mockito.Matchers.anyString;
+import static org.mockito.Mockito.mock;
+
+import java.io.IOException;
+
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.testing.MojoRule;
+import org.apache.maven.plugin.testing.resources.TestResources;
+import org.apache.maven.project.MavenProject;
+import org.apache.servicecomb.toolkit.common.FileUtils;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+import org.powermock.api.mockito.PowerMockito;
+import org.powermock.core.classloader.annotations.PrepareForTest;
+import org.powermock.modules.junit4.PowerMockRunner;
+
+@RunWith(PowerMockRunner.class)
+@PrepareForTest({FileUtils.class, GenerateUtil.class})
+public class InvokeStaticMethodTest {
+
+  @Rule
+  public MojoRule rule = new MojoRule();
+
+  @Rule
+  public TestResources resources = new TestResources();
+
+  private TestResourcesEx testGenerateMojoResources;
+
+  private TestResourcesEx testVerifyMojoResources;
+
+  @Before
+  public void setUp() throws Exception {
+
+    testGenerateMojoResources = new TestResourcesEx(resources);
+    testVerifyMojoResources = new TestResourcesEx(resources);
+
+    String testDirWithContract = testGenerateMojoResources.getBasedirWithContract();
+    testGenerateMojoResources.createMojo(rule, testDirWithContract, "generate");
+    testVerifyMojoResources.createMojo(rule, testDirWithContract, "verify");
+
+    MavenProject project = mock(MavenProject.class);
+    testGenerateMojoResources.setVariableValueToObject("project", project);
+    testVerifyMojoResources.setVariableValueToObject("project", project);
+
+    given(project.getRuntimeClasspathElements())
+        .willReturn(testGenerateMojoResources.getRuntimeUrlPath(testDirWithContract));
+    given(project.getRuntimeClasspathElements())
+        .willReturn(testVerifyMojoResources.getRuntimeUrlPath(testDirWithContract));
+  }
+
+  @Test
+  public void testVerifyMojoInvokeGenerateUtilGenerateContract()
+      throws MojoFailureException, MojoExecutionException, IllegalAccessException {
+
+    PowerMockito.mockStatic(GenerateUtil.class);
+    PowerMockito.doThrow(new RuntimeException()).when(GenerateUtil.class);
+    // Powermockito limit: use argument matchers to specify method which would be mock
+    GenerateUtil.generateContract(anyObject(), anyString(), anyString(), anyString());
+
+    testVerifyMojoResources.setVariableValueToObject("sourceType", "code");
+    try {
+      testVerifyMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate contract from code", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("RuntimeException"));
+      return;
+    }
+
+    fail("Run 'testVerifyMojoInvokeGenerateUtilGenerateContract' failed, expected to catch RuntimeException but not");
+  }
+
+  @Test
+  public void testVerifyMojoInvokeFileUtilsCreateTempDirectory()
+      throws MojoFailureException, MojoExecutionException, IllegalAccessException, IOException {
+
+    PowerMockito.mockStatic(FileUtils.class);
+    PowerMockito.doThrow(new IOException()).when(FileUtils.class);
+    // Powermockito limit: use argument matchers to specify method which would be mock
+    FileUtils.createTempDirectory(anyString());
+
+    testVerifyMojoResources.setVariableValueToObject("sourceType", "code");
+    try {
+      testVerifyMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate contract from code", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("IOException"));
+      return;
+    }
+
+    fail("Run 'testVerifyMojoInvokeFileUtilsCreateTempDirectory' failed, expected to catch RuntimeException but not");
+  }
+
+  @Test
+  public void testGenerateMojoInvokeFileUtilsCreateDirectory()
+      throws IllegalAccessException, MojoFailureException, MojoExecutionException, IOException {
+
+    PowerMockito.mockStatic(FileUtils.class);
+    PowerMockito.doThrow(new IOException()).when(FileUtils.class);
+    // Powermockito limit: use argument matchers to specify method which would be mock
+    FileUtils.createDirectory(anyString());
+
+    testGenerateMojoResources.setVariableValueToObject("sourceType", "code");
+    try {
+      testGenerateMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate contract", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("IOException"));
+      return;
+    }
+
+    fail("Run 'testGenerateMojoInvokeFileUtilsCreateDirectory' failed, expected to catch RuntimeException but not");
+  }
+
+  @Test
+  public void testGenerateMojoInvokeGenerateUtilGenerateCode()
+      throws IllegalAccessException, MojoFailureException, MojoExecutionException, IOException {
+
+    boolean succeed = false;
+
+    PowerMockito.mockStatic(GenerateUtil.class);
+    PowerMockito.doThrow(new IOException()).when(GenerateUtil.class);
+    // Powermockito limit: use argument matchers to specify method which would be mock
+    GenerateUtil.generateCode(anyObject(), anyString(), anyString(), anyString());
+
+    testGenerateMojoResources.setVariableValueToObject("sourceType", "contract");
+    testGenerateMojoResources
+        .setVariableValueToObject("contractLocation", testGenerateMojoResources.getContractLocation());
+    testGenerateMojoResources.setVariableValueToObject("service", new ServiceConfig());
+    try {
+      testGenerateMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate code", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("IOException"));
+      succeed = true;
+    }
+    assertTrue(succeed);
+
+    PowerMockito.doThrow(new RuntimeException()).when(GenerateUtil.class);
+    GenerateUtil.generateCode(anyObject(), anyString(), anyString(), anyString());
+    try {
+      testGenerateMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate code", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("RuntimeException"));
+      return;
+    }
+
+    fail("Run 'testGenerateMojoInvokeGenerateUtilGenerateCode' failed, expected to catch RuntimeException but not");
+  }
+
+  @Test
+  public void testGenerateMojoInvokeGenerateUtilGenerateDocument()
+      throws IllegalAccessException, MojoFailureException, MojoExecutionException, IOException {
+
+    boolean succeed = false;
+
+    PowerMockito.mockStatic(GenerateUtil.class);
+    PowerMockito.doThrow(new IOException()).when(GenerateUtil.class);
+    // Powermockito limit: use argument matchers to specify method which would be mock
+    GenerateUtil.generateDocument(anyString(), anyString(), anyString());
+
+    testGenerateMojoResources.setVariableValueToObject("sourceType", "contract");
+    testGenerateMojoResources
+        .setVariableValueToObject("contractLocation", testGenerateMojoResources.getContractLocation());
+    testGenerateMojoResources.setVariableValueToObject("service", new ServiceConfig());
+    try {
+      testGenerateMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate document", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("IOException"));
+      succeed = true;
+    }
+    assertTrue(succeed);
+
+    PowerMockito.doThrow(new RuntimeException()).when(GenerateUtil.class);
+    GenerateUtil.generateDocument(anyString(), anyString(), anyString());
+    try {
+      testGenerateMojoResources.execute();
+    } catch (RuntimeException e) {
+      assertEquals("Failed to generate document", e.getMessage());
+      assertThat(e.getCause().toString(), containsString("RuntimeException"));
+      return;
+    }
+
+    fail("Run 'testGenerateMojoInvokeGenerateUtilGenerateDocument' failed, expected to catch RuntimeException but not");
+  }
+}
diff --git a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/TestResourcesEx.java b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/TestResourcesEx.java
new file mode 100644
index 0000000..5796d50
--- /dev/null
+++ b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/TestResourcesEx.java
@@ -0,0 +1,101 @@
+/*
+ * 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.servicecomb.toolkit.plugin;
+
+import java.io.File;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.concurrent.TimeoutException;
+
+import org.apache.maven.plugin.AbstractMojo;
+import org.apache.maven.plugin.MojoExecutionException;
+import org.apache.maven.plugin.MojoFailureException;
+import org.apache.maven.plugin.testing.MojoRule;
+import org.apache.maven.plugin.testing.resources.TestResources;
+import org.apache.servicecomb.toolkit.common.ClassMaker;
+
+public class TestResourcesEx {
+
+  private String basedirWithContract;
+
+  private String basedirWithoutContract;
+
+  private String contractLocation;
+
+  private String contractDestination;
+
+  private AbstractMojo testMojo;
+
+  private MojoRule rule;
+
+  TestResourcesEx(TestResources resources) throws Exception {
+
+    this.basedirWithContract = resources.getBasedir("demo-with-contract") + File.separator;
+    this.basedirWithoutContract = resources.getBasedir("demo-without-contract") + File.separator;
+    this.contractLocation = resources.getBasedir("contract-source") + File.separator;
+    this.contractDestination = resources.getBasedir("contract-destination") + File.separator;
+  }
+
+  void createMojo(MojoRule rule, String basedir, String pluginGoal) throws Exception {
+
+    this.rule = rule;
+
+    File pomPath = new File(basedir, "pom.xml");
+    this.testMojo = (AbstractMojo) this.rule.lookupMojo(pluginGoal, pomPath);
+  }
+
+  void setVariableValueToObject(String variable, Object value) throws IllegalAccessException {
+    this.rule.setVariableValueToObject(this.testMojo, variable, value);
+  }
+
+  String getVariableValueFromObject(String variable) throws IllegalAccessException {
+    return (String) this.rule.getVariableValueFromObject(this.testMojo, variable);
+  }
+
+  String getBasedirWithContract() {
+    return basedirWithContract;
+  }
+
+  String getBasedirWithoutContract() {
+    return basedirWithoutContract;
+  }
+
+  String getContractLocation() {
+    return contractLocation;
+  }
+
+  public String getContractDestination() {
+    return contractDestination;
+  }
+
+  void execute() throws MojoFailureException, MojoExecutionException {
+    this.testMojo.execute();
+  }
+
+  List<String> getRuntimeUrlPath(String basedir) throws InterruptedException, TimeoutException, IOException {
+
+    ClassMaker.compile(basedir);
+
+    List<String> runtimeUrlPath = new ArrayList<>();
+
+    runtimeUrlPath.add(basedir + "target" + File.separator + "classes");
+
+    return runtimeUrlPath;
+  }
+}
diff --git a/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/VerifyMojoTest.java b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/VerifyMojoTest.java
new file mode 100644
index 0000000..45e6dd7
--- /dev/null
+++ b/toolkit-maven-plugin/src/test/java/org/apache/servicecomb/toolkit/plugin/VerifyMojoTest.java
@@ -0,0 +1,96 @@
+/*
+ * 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.servicecomb.toolkit.plugin;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.junit.Assert.assertThat;
+import static org.junit.Assert.assertTrue;
+import static org.junit.Assert.fail;
+import static org.mockito.BDDMockito.given;
+import static org.mockito.Mockito.mock;
+
+import org.apache.maven.plugin.testing.MojoRule;
+import org.apache.maven.plugin.testing.resources.TestResources;
+import org.apache.maven.project.MavenProject;
+import org.junit.Rule;
+import org.junit.Test;
+
+public class VerifyMojoTest {
+
+  @Rule
+  public MojoRule rule = new MojoRule();
+
+  @Rule
+  public TestResources resources = new TestResources();
+
+  boolean succeed;
+
+  @Test
+  public void testVerifyMojo() throws Exception {
+
+    TestResourcesEx testResourcesEx = new TestResourcesEx(resources);
+
+    String testDirWithContract = testResourcesEx.getBasedirWithContract();
+
+    testResourcesEx.createMojo(rule, testDirWithContract, "verify");
+
+    MavenProject project = mock(MavenProject.class);
+    testResourcesEx.setVariableValueToObject("project", project);
+
+    try {
+      given(project.getRuntimeClasspathElements()).willReturn(testResourcesEx.getRuntimeUrlPath(testDirWithContract));
+      testResourcesEx.setVariableValueToObject("sourceType", "code");
+      testResourcesEx.setVariableValueToObject("destinationContractPath", testResourcesEx.getContractDestination());
+      testResourcesEx.execute();
+    } catch (RuntimeException e) {
+      fail("Run 'testVerifyMojo' failed and unexpected to catch RuntimeException: " + e.getMessage());
+    }
+
+    try {
+      succeed = false;
+      testResourcesEx.setVariableValueToObject("sourceType", "contract");
+      testResourcesEx.setVariableValueToObject("sourceContractPath", null);
+      testResourcesEx.execute();
+    } catch (RuntimeException e) {
+      assertThat(e.getMessage(), containsString("Failed to verify contract"));
+      succeed = true;
+    }
+    assertTrue(succeed);
+
+    try {
+      succeed = false;
+      testResourcesEx.setVariableValueToObject("sourceType", "contract");
+      testResourcesEx.setVariableValueToObject("sourceContractPath", testResourcesEx.getContractLocation());
+      testResourcesEx.setVariableValueToObject("destinationContractPath", null);
+      testResourcesEx.execute();
+    } catch (RuntimeException e) {
+      assertThat(e.getMessage(), containsString("Failed to verify contract"));
+      succeed = true;
+    }
+    assertTrue(succeed);
+
+    try {
+      testResourcesEx.setVariableValueToObject("sourceType", "contract");
+      testResourcesEx.setVariableValueToObject("sourceContractPath", testResourcesEx.getContractLocation());
+      testResourcesEx.setVariableValueToObject("destinationContractPath", testResourcesEx.getContractDestination());
+      testResourcesEx.execute();
+    } catch (RuntimeException e) {
+      fail("Run 'testVerifyMojo' failed and unexpected to catch RuntimeException: " + e.getMessage());
+    }
+  }
+}
\ No newline at end of file
diff --git a/toolkit-maven-plugin/src/test/projects/contract-destination/HelloEndPoint.yaml b/toolkit-maven-plugin/src/test/projects/contract-destination/HelloEndPoint.yaml
new file mode 100644
index 0000000..f121879
--- /dev/null
+++ b/toolkit-maven-plugin/src/test/projects/contract-destination/HelloEndPoint.yaml
@@ -0,0 +1,55 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+---
+swagger: "2.0"
+info:
+  version: "1.0.0"
+  title: "swagger definition for demo.HelloEndPoint"
+  x-java-interface: "gen.swagger.HelloEndPointIntf"
+basePath: "/hello"
+consumes:
+- "application/json"
+produces:
+- "application/json"
+paths:
+  /sayHello:
+    get:
+      operationId: "sayHello"
+      parameters:
+      - name: "name"
+        in: "query"
+        required: require
+        type: "string"
+      responses:
+        200:
+          description: "response of 200"
+          schema:
+            type: "string"
+  /sayHi:
+    get:
+      operationId: "sayHi"
+      parameters:
+      - name: "name"
+        in: "query"
+        required: false
+        type: "string"
+      responses:
+        200:
+          description: "response of 200"
+          schema:
+            type: "string"
diff --git a/toolkit-maven-plugin/src/test/projects/contract-source/HelloEndPoint.yaml b/toolkit-maven-plugin/src/test/projects/contract-source/HelloEndPoint.yaml
new file mode 100644
index 0000000..182d941
--- /dev/null
+++ b/toolkit-maven-plugin/src/test/projects/contract-source/HelloEndPoint.yaml
@@ -0,0 +1,55 @@
+## ---------------------------------------------------------------------------
+## Licensed to the Apache Software Foundation (ASF) under one or more
+## contributor license agreements.  See the NOTICE file distributed with
+## this work for additional information regarding copyright ownership.
+## The ASF licenses this file to You under the Apache License, Version 2.0
+## (the "License"); you may not use this file except in compliance with
+## the License.  You may obtain a copy of the License at
+##
+##      http://www.apache.org/licenses/LICENSE-2.0
+##
+## Unless required by applicable law or agreed to in writing, software
+## distributed under the License is distributed on an "AS IS" BASIS,
+## WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+## See the License for the specific language governing permissions and
+## limitations under the License.
+## ---------------------------------------------------------------------------
+
+---
+swagger: "2.0"
+info:
+  version: "1.0.0"
+  title: "swagger definition for demo.HelloEndPoint"
+  x-java-interface: "gen.swagger.HelloEndPointIntf"
+basePath: "/hello"
+consumes:
+- "application/json"
+produces:
+- "application/json"
+paths:
+  /sayHello:
+    get:
+      operationId: "sayHello"
+      parameters:
+      - name: "name"
+        in: "query"
+        required: false
+        type: "string"
+      responses:
+        200:
+          description: "response of 200"
+          schema:
+            type: "string"
+  /sayHi:
+    get:
+      operationId: "sayHi"
+      parameters:
+      - name: "name"
+        in: "query"
+        required: false
+        type: "string"
+      responses:
+        200:
+          description: "response of 200"
+          schema:
+            type: "string"
diff --git a/toolkit-maven-plugin/src/test/projects/contract/swagger.yaml b/toolkit-maven-plugin/src/test/projects/contract/swagger.yaml
deleted file mode 100755
index b97799c..0000000
--- a/toolkit-maven-plugin/src/test/projects/contract/swagger.yaml
+++ /dev/null
@@ -1,707 +0,0 @@
----
-swagger: "2.0"
-info:
-  description: "This is a sample server Petstore server.  You can find out more about\
-    \ Swagger at [http://swagger.io](http://swagger.io) or on [irc.freenode.net, #swagger](http://swagger.io/irc/).\
-    \  For this sample, you can use the api key `special-key` to test the authorization\
-    \ filters."
-  version: "1.0.0"
-  title: "Swagger Petstore"
-  termsOfService: "http://swagger.io/terms/"
-  contact:
-    email: "apiteam@swagger.io"
-  license:
-    name: "Apache 2.0"
-    url: "http://www.apache.org/licenses/LICENSE-2.0.html"
-host: "petstore.swagger.io"
-basePath: "/v2"
-tags:
-- name: "pet"
-  description: "Everything about your Pets"
-  externalDocs:
-    description: "Find out more"
-    url: "http://swagger.io"
-- name: "store"
-  description: "Access to Petstore orders"
-- name: "user"
-  description: "Operations about user"
-  externalDocs:
-    description: "Find out more about our store"
-    url: "http://swagger.io"
-schemes:
-- "https"
-- "http"
-paths:
-  /pet:
-    post:
-      tags:
-      - "pet"
-      summary: "Add a new pet to the store"
-      description: ""
-      operationId: "addPet"
-      consumes:
-      - "application/json"
-      - "application/xml"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        description: "Pet object that needs to be added to the store"
-        required: true
-        schema:
-          $ref: "#/definitions/Pet"
-      responses:
-        405:
-          description: "Invalid input"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-    put:
-      tags:
-      - "pet"
-      summary: "Update an existing pet"
-      description: ""
-      operationId: "updatePet"
-      consumes:
-      - "application/json"
-      - "application/xml"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        description: "Pet object that needs to be added to the store"
-        required: true
-        schema:
-          $ref: "#/definitions/Pet"
-      responses:
-        400:
-          description: "Invalid ID supplied"
-        404:
-          description: "Pet not found"
-        405:
-          description: "Validation exception"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-  /pet/findByStatus:
-    get:
-      tags:
-      - "pet"
-      summary: "Finds Pets by status"
-      description: "Multiple status values can be provided with comma separated strings"
-      operationId: "findPetsByStatus"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "status"
-        in: "query"
-        description: "Status values that need to be considered for filter"
-        required: true
-        type: "array"
-        items:
-          type: "string"
-          enum:
-          - "available"
-          - "pending"
-          - "sold"
-          default: "available"
-        collectionFormat: "multi"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "array"
-            items:
-              $ref: "#/definitions/Pet"
-        400:
-          description: "Invalid status value"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-  /pet/findByTags:
-    get:
-      tags:
-      - "pet"
-      summary: "Finds Pets by tags"
-      description: "Multiple tags can be provided with comma separated strings. Use\
-        \ tag1, tag2, tag3 for testing."
-      operationId: "findPetsByTags"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "tags"
-        in: "query"
-        description: "Tags to filter by"
-        required: true
-        type: "array"
-        items:
-          type: "string"
-        collectionFormat: "multi"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "array"
-            items:
-              $ref: "#/definitions/Pet"
-        400:
-          description: "Invalid tag value"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-      deprecated: true
-  /pet/{petId}:
-    get:
-      tags:
-      - "pet"
-      summary: "Find pet by ID"
-      description: "Returns a single pet"
-      operationId: "getPetById"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "petId"
-        in: "path"
-        description: "ID of pet to return"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/Pet"
-        400:
-          description: "Invalid ID supplied"
-        404:
-          description: "Pet not found"
-      security:
-      - api_key: []
-    post:
-      tags:
-      - "pet"
-      summary: "Updates a pet in the store with form data"
-      description: ""
-      operationId: "updatePetWithForm"
-      consumes:
-      - "application/x-www-form-urlencoded"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "petId"
-        in: "path"
-        description: "ID of pet that needs to be updated"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "name"
-        in: "formData"
-        description: "Updated name of the pet"
-        required: false
-        type: "string"
-      - name: "status"
-        in: "formData"
-        description: "Updated status of the pet"
-        required: false
-        type: "string"
-      responses:
-        405:
-          description: "Invalid input"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-    delete:
-      tags:
-      - "pet"
-      summary: "Deletes a pet"
-      description: ""
-      operationId: "deletePet"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "api_key"
-        in: "header"
-        required: false
-        type: "string"
-      - name: "petId"
-        in: "path"
-        description: "Pet id to delete"
-        required: true
-        type: "integer"
-        format: "int64"
-      responses:
-        400:
-          description: "Invalid ID supplied"
-        404:
-          description: "Pet not found"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-  /pet/{petId}/uploadImage:
-    post:
-      tags:
-      - "pet"
-      summary: "uploads an image"
-      description: ""
-      operationId: "uploadFile"
-      consumes:
-      - "multipart/form-data"
-      produces:
-      - "application/json"
-      parameters:
-      - name: "petId"
-        in: "path"
-        description: "ID of pet to update"
-        required: true
-        type: "integer"
-        format: "int64"
-      - name: "additionalMetadata"
-        in: "formData"
-        description: "Additional data to pass to server"
-        required: false
-        type: "string"
-      - name: "file"
-        in: "formData"
-        description: "file to upload"
-        required: false
-        type: "file"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/ApiResponse"
-      security:
-      - petstore_auth:
-        - "write:pets"
-        - "read:pets"
-  /store/inventory:
-    get:
-      tags:
-      - "store"
-      summary: "Returns pet inventories by status"
-      description: "Returns a map of status codes to quantities"
-      operationId: "getInventory"
-      produces:
-      - "application/json"
-      parameters: []
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "object"
-            additionalProperties:
-              type: "integer"
-              format: "int32"
-      security:
-      - api_key: []
-  /store/order:
-    post:
-      tags:
-      - "store"
-      summary: "Place an order for a pet"
-      description: ""
-      operationId: "placeOrder"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        description: "order placed for purchasing the pet"
-        required: true
-        schema:
-          $ref: "#/definitions/Order"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/Order"
-        400:
-          description: "Invalid Order"
-  /store/order/{orderId}:
-    get:
-      tags:
-      - "store"
-      summary: "Find purchase order by ID"
-      description: "For valid response try integer IDs with value >= 1 and <= 10.\
-        \ Other values will generated exceptions"
-      operationId: "getOrderById"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "orderId"
-        in: "path"
-        description: "ID of pet that needs to be fetched"
-        required: true
-        type: "integer"
-        maximum: 10.0
-        minimum: 1.0
-        format: "int64"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/Order"
-        400:
-          description: "Invalid ID supplied"
-        404:
-          description: "Order not found"
-    delete:
-      tags:
-      - "store"
-      summary: "Delete purchase order by ID"
-      description: "For valid response try integer IDs with positive integer value.\
-        \ Negative or non-integer values will generate API errors"
-      operationId: "deleteOrder"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "orderId"
-        in: "path"
-        description: "ID of the order that needs to be deleted"
-        required: true
-        type: "integer"
-        minimum: 1.0
-        format: "int64"
-      responses:
-        400:
-          description: "Invalid ID supplied"
-        404:
-          description: "Order not found"
-  /user:
-    post:
-      tags:
-      - "user"
-      summary: "Create user"
-      description: "This can only be done by the logged in user."
-      operationId: "createUser"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        description: "Created user object"
-        required: true
-        schema:
-          $ref: "#/definitions/User"
-      responses:
-        default:
-          description: "successful operation"
-  /user/createWithArray:
-    post:
-      tags:
-      - "user"
-      summary: "Creates list of users with given input array"
-      description: ""
-      operationId: "createUsersWithArrayInput"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        description: "List of user object"
-        required: true
-        schema:
-          type: "array"
-          items:
-            $ref: "#/definitions/User"
-      responses:
-        default:
-          description: "successful operation"
-  /user/createWithList:
-    post:
-      tags:
-      - "user"
-      summary: "Creates list of users with given input array"
-      description: ""
-      operationId: "createUsersWithListInput"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - in: "body"
-        name: "body"
-        description: "List of user object"
-        required: true
-        schema:
-          type: "array"
-          items:
-            $ref: "#/definitions/User"
-      responses:
-        default:
-          description: "successful operation"
-  /user/login:
-    get:
-      tags:
-      - "user"
-      summary: "Logs user into the system"
-      description: ""
-      operationId: "loginUser"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "username"
-        in: "query"
-        description: "The user name for login"
-        required: true
-        type: "string"
-      - name: "password"
-        in: "query"
-        description: "The password for login in clear text"
-        required: true
-        type: "string"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            type: "string"
-          headers:
-            X-Rate-Limit:
-              type: "integer"
-              format: "int32"
-              description: "calls per hour allowed by the user"
-            X-Expires-After:
-              type: "string"
-              format: "date-time"
-              description: "date in UTC when token expires"
-        400:
-          description: "Invalid username/password supplied"
-  /user/logout:
-    get:
-      tags:
-      - "user"
-      summary: "Logs out current logged in user session"
-      description: ""
-      operationId: "logoutUser"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters: []
-      responses:
-        default:
-          description: "successful operation"
-  /user/{username}:
-    get:
-      tags:
-      - "user"
-      summary: "Get user by user name"
-      description: ""
-      operationId: "getUserByName"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "username"
-        in: "path"
-        description: "The name that needs to be fetched. Use user1 for testing. "
-        required: true
-        type: "string"
-      responses:
-        200:
-          description: "successful operation"
-          schema:
-            $ref: "#/definitions/User"
-        400:
-          description: "Invalid username supplied"
-        404:
-          description: "User not found"
-    put:
-      tags:
-      - "user"
-      summary: "Updated user"
-      description: "This can only be done by the logged in user."
-      operationId: "updateUser"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "username"
-        in: "path"
-        description: "name that need to be updated"
-        required: true
-        type: "string"
-      - in: "body"
-        name: "body"
-        description: "Updated user object"
-        required: true
-        schema:
-          $ref: "#/definitions/User"
-      responses:
-        400:
-          description: "Invalid user supplied"
-        404:
-          description: "User not found"
-    delete:
-      tags:
-      - "user"
-      summary: "Delete user"
-      description: "This can only be done by the logged in user."
-      operationId: "deleteUser"
-      produces:
-      - "application/xml"
-      - "application/json"
-      parameters:
-      - name: "username"
-        in: "path"
-        description: "The name that needs to be deleted"
-        required: true
-        type: "string"
-      responses:
-        400:
-          description: "Invalid username supplied"
-        404:
-          description: "User not found"
-securityDefinitions:
-  petstore_auth:
-    type: "oauth2"
-    authorizationUrl: "https://petstore.swagger.io/oauth/authorize"
-    flow: "implicit"
-    scopes:
-      write:pets: "modify pets in your account"
-      read:pets: "read your pets"
-  api_key:
-    type: "apiKey"
-    name: "api_key"
-    in: "header"
-definitions:
-  Order:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      petId:
-        type: "integer"
-        format: "int64"
-      quantity:
-        type: "integer"
-        format: "int32"
-      shipDate:
-        type: "string"
-        format: "date-time"
-      status:
-        type: "string"
-        description: "Order Status"
-        enum:
-        - "placed"
-        - "approved"
-        - "delivered"
-      complete:
-        type: "boolean"
-        default: false
-    xml:
-      name: "Order"
-  User:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      username:
-        type: "string"
-      firstName:
-        type: "string"
-      lastName:
-        type: "string"
-      email:
-        type: "string"
-      password:
-        type: "string"
-      phone:
-        type: "string"
-      userStatus:
-        type: "integer"
-        format: "int32"
-        description: "User Status"
-    xml:
-      name: "User"
-  Category:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      name:
-        type: "string"
-    xml:
-      name: "Category"
-  Tag:
-    type: "object"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      name:
-        type: "string"
-    xml:
-      name: "Tag"
-  Pet:
-    type: "object"
-    required:
-    - "name"
-    - "photoUrls"
-    properties:
-      id:
-        type: "integer"
-        format: "int64"
-      category:
-        $ref: "#/definitions/Category"
-      name:
-        type: "string"
-        example: "doggie"
-      photoUrls:
-        type: "array"
-        xml:
-          name: "photoUrl"
-          wrapped: true
-        items:
-          type: "string"
-      tags:
-        type: "array"
-        xml:
-          name: "tag"
-          wrapped: true
-        items:
-          $ref: "#/definitions/Tag"
-      status:
-        type: "string"
-        description: "pet status in the store"
-        enum:
-        - "available"
-        - "pending"
-        - "sold"
-    xml:
-      name: "Pet"
-  ApiResponse:
-    type: "object"
-    properties:
-      code:
-        type: "integer"
-        format: "int32"
-      type:
-        type: "string"
-      message:
-        type: "string"
-externalDocs:
-  description: "Find out more about Swagger"
-  url: "http://swagger.io"