Repository: authorjapps/zerocode
Pull request #267 (2019-07-01 11:23:26)

ISS-258 # Support Scenario annotation(low priority - user request)
Final bit in WIP_(In Progress) in this PR, but you can start reviewing...


Patch:
diff --git a/README.md b/README.md
index 22a02ce6..90ac66c1 100644
--- a/README.md
+++ b/README.md
@@ -55,28 +55,13 @@ then, we can easily validate the above API using `Zerocode` like below.
 
 Or
 
-```javaScript
-{
-    ...
-    "verifications": {
-        "status": 200,
-        "body": {
-            "id": 123,
-            "addresses.SIZE": 1  // Only array length validation, not the contents
-        }
-    }
-}
-```
-
-Or
-
 ```javaScript
 {
     ...
     "verifications": {
         "body": {
             "id": "$NOT.NULL",  // A not-null indeterministic value
-            "addresses.SIZE": "$GT.0"  // A value greater than 0
+            "addresses.SIZE": "$GT.0"  // Only the length validation(not the contents) - Greater Than 0. 
         }
     }
 }
@@ -112,7 +97,7 @@ and run it simply by pointing to the above JSON file from a "JUnit" @Test method
 
 ```java
    @Test
-   @JsonTestCase("test_customer_get_api.json")
+   @Scenario("test_customer_get_api.json")
    public void getCustomerHappy(){
         // No code goes here. This remains empty.
    }
@@ -147,32 +132,35 @@ e.g.
 public class GitHubHelloWorldTest {
 
    @Test
-   @JsonTestCase("screening_tests/test_happy_flow.json")
+   @Scenario("screening_tests/test_happy_flow.json")
    public void testHappyFlow(){
    }
 
    @Test
-   @JsonTestCase("screening_tests/test_negative_flow.json")
+   @Scenario("screening_tests/test_negative_flow.json")
    public void testNegativeFlow(){
    }
 
 }
-
 ```
 
 Running a Suite of Tests
 ===
 `ZeroCodePackageRunner` is the JUnit runner which enables us to run a pack/suite of tests from the test resources folder.
 e.g.
-+ Selecting all tests from a resource folder
+
++ Selecting as usual `JUnit Suite`
+
 ```java
-@TargetEnv("app_sit1.properties")
-@TestPackageRoot("screening_tests") //<--- Root of the package to pick all tests including sub-folders
-@RunWith(ZeroCodePackageRunner.class)
-public class ScreeningTestSuite {
-    // This class remains empty	
-}
+@RunWith(Suite.class)				
+@Suite.SuiteClasses({				
+  HelloWorldSimpleTest.class,
+  HelloWorldMoreTest.class,  			
+})		
 
+public class HelloWorldJunitSuite {
+    // This class remains empty		
+}
 ```
 
 Or
@@ -181,9 +169,9 @@ Or
 @TargetEnv("app_dev1.properties")
 @UseHttpClient(CustomHttpClient.class)
 @RunWith(ZeroCodePackageRunner.class)
-@JsonTestCases({
-        @JsonTestCase("path1/test_case_scenario_1.json"),
-        @JsonTestCase("path2/test_case_scenario_2.json"),
+@Scenarios({
+        @Scenario("path1/test_case_scenario_1.json"),
+        @Scenario("path2/test_case_scenario_2.json"),
 })
 public class HelloWorldSelectedGitHubSuite {
     // This class remains empty
@@ -191,20 +179,20 @@ public class HelloWorldSelectedGitHubSuite {
 ```
 
 Or
-+ Selecting as usual `JUnit Suite`
 
++ Selecting all tests from a resource folder
 ```java
-@RunWith(Suite.class)				
-@Suite.SuiteClasses({				
-  HelloWorldSimpleTest.class,
-  HelloWorldMoreTest.class,  			
-})		
-
-public class HelloWorldJunitSuite {
-    // This class remains empty		
+@TargetEnv("app_sit1.properties")
+@TestPackageRoot("screening_tests") //<--- Root of the package to pick all tests including sub-folders
+@RunWith(ZeroCodePackageRunner.class)
+public class ScreeningTestSuite {
+    // This class remains empty	
 }
 ```
 
+Load Testing
+===
+Use Zerocode declarative [parallel load generation](https://github.com/authorjapps/zerocode/blob/master/README.md#generating-load-for-performance-testing-aka-stress-testing) on the target system.
 
 Declarative TestCase - Hooking BDD Scenario Steps
 ===
@@ -225,7 +213,7 @@ web.application.endpoint.host=https://api.github.com
 web.application.endpoint.port=443
 ```
 
-e.g. Our below User-Journey or ACs(Acceptance Criterias) or a scenario,
+e.g. Our below User-Journey or AC(Acceptance Criteria) or a Scenario,
 ```JSON
 AC1:
 GIVEN- the POST api end point '/api/v1/users' to create an user,     
@@ -418,7 +406,7 @@ That's it. Done.
 public class JustHelloWorldTest {
 
     @Test
-    @JsonTestCase("helloworld/hello_world_status_ok_assertions.json")
+    @Scenario("helloworld/hello_world_status_ok_assertions.json")
     public void testGet() throws Exception {
 
     }
@@ -1400,7 +1388,7 @@ The runner looks like this:
 public class ScreeningServiceContractTest {
 
     @Test
-    @JsonTestCase("contract_tests/screeningservice/get_screening_details_by_custid.json")
+    @Scenario("contract_tests/screeningservice/get_screening_details_by_custid.json")
     public void testScreeningLocalAndGlobal() throws Exception {
     }
 }
@@ -1436,7 +1424,7 @@ public class ScreeningServiceContractTest {
 public class JustHelloWorldTest {
 
     @Test
-    @JsonTestCase("helloworld/hello_world_status_ok_assertions.json")
+    @Scenario("helloworld/hello_world_status_ok_assertions.json")
     public void testGet() throws Exception {
 
     }
@@ -1585,7 +1573,7 @@ Also the framework enables you to override this behaviour/handling by overriding
 package org.jsmart.zerocode.testhelp.tests;
 
 import org.jsmart.zerocode.core.domain.EnvProperty;
-import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.Scenario;
 import org.jsmart.zerocode.core.domain.TargetEnv;
 import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
 import org.junit.Test;
@@ -1597,7 +1585,7 @@ import org.junit.runner.RunWith;
 public class EnvPropertyHelloWorldTest {
 
     @Test
-    @JsonTestCase("hello_world/hello_world_get.json")
+    @Scenario("hello_world/hello_world_get.json")
     public void testRunAgainstConfigPropertySetViaJenkins() throws Exception {
         
     }
@@ -1837,7 +1825,7 @@ public class SoapCorpProxySslHttpClientTest {
 
     @Ignore
     @Test
-    @JsonTestCase("foo/bar/soap_test_case_file.json")
+    @Scenario("foo/bar/soap_test_case_file.json")
     public void testSoapWithCorpProxyEnabled() throws Exception {
 
     }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/Scenario.java b/core/src/main/java/org/jsmart/zerocode/core/domain/Scenario.java
new file mode 100644
index 00000000..cf30272f
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/Scenario.java
@@ -0,0 +1,11 @@
+package org.jsmart.zerocode.core.domain;
+
+import java.lang.annotation.Repeatable;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+
+@Retention(RetentionPolicy.RUNTIME)
+@Repeatable( value = Scenarios.class )
+public @interface Scenario {
+    String value();
+}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/domain/Scenarios.java b/core/src/main/java/org/jsmart/zerocode/core/domain/Scenarios.java
new file mode 100644
index 00000000..dd32bef5
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/domain/Scenarios.java
@@ -0,0 +1,13 @@
+package org.jsmart.zerocode.core.domain;
+
+
+import java.lang.annotation.ElementType;
+import java.lang.annotation.Retention;
+import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.Target;
+
+@Target(ElementType.TYPE)
+@Retention(RetentionPolicy.RUNTIME)
+public @interface Scenarios {
+    public Scenario[] value() default {};
+}
\ No newline at end of file
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ScenarioExecutionState.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ScenarioExecutionState.java
index df435faf..c23c4505 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ScenarioExecutionState.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ScenarioExecutionState.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (C) 2014 jApps Ltd and
- * Copyright 2016 the original author or authors.
- *
- * Licensed 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.jsmart.zerocode.core.engine.preprocessor;
 
 import org.apache.commons.lang.text.StrSubstitutor;
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/StepExecutionState.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/StepExecutionState.java
index 384c7e1c..e8730b68 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/StepExecutionState.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/StepExecutionState.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (C) 2014 jApps Ltd and
- * Copyright 2016 the original author or authors.
- *
- * Licensed 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.jsmart.zerocode.core.engine.preprocessor;
 
 import org.apache.commons.lang.text.StrSubstitutor;
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessor.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessor.java
index d6c34f47..303cfca1 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessor.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessor.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (C) 2014 jApps Ltd and
- * Copyright 2016 the original author or authors.
- *
- * Licensed 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.jsmart.zerocode.core.engine.preprocessor;
 
 import org.jsmart.zerocode.core.domain.Step;
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java
index e7acad54..9a225b25 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeExternalFileProcessorImpl.java
@@ -1,20 +1,3 @@
-/*
- * Copyright (C) 2014 jApps Ltd and
- * Copyright 2016 the original author or authors.
- *
- * Licensed 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.jsmart.zerocode.core.engine.preprocessor;
 
 import com.fasterxml.jackson.core.JsonProcessingException;
@@ -51,8 +34,6 @@ import static org.slf4j.LoggerFactory.getLogger;
  * test case itself. We should use the IDE features which now a days makes a lot easier in terms of dealing with
  * JSON contents to keep the testing life cycle simple.
  *
- * @author nirmal.fleet@google.com (Nirmal Chandra)
- * @author ghorpade.a.g@gmail.com (Amit Ghorpade)
  */
 @Singleton
 public class ZeroCodeExternalFileProcessorImpl implements ZeroCodeExternalFileProcessor {
diff --git a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java
index 7bc804fa..f86ba2e6 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeMultiStepsScenarioRunnerImpl.java
@@ -235,9 +235,10 @@ public class ZeroCodeMultiStepsScenarioRunnerImpl implements ZeroCodeMultiStepsS
                                 scenarioExecutionState.getResolvedScenarioState()
                         );
 
+                        // -----------------
                         // logging assertion
-
-                        List<JsonAsserter> asserters = zeroCodeJsonTestProcesor.createAssertersFrom(resolvedAssertionJson);
+                        // -----------------
+                        List<JsonAsserter> asserters = zeroCodeJsonTestProcesor.createJsonAsserters(resolvedAssertionJson);
                         List<AssertionReport> failureResults = zeroCodeJsonTestProcesor.assertAllAndReturnFailed(asserters, executionResult);
 
                         if (!failureResults.isEmpty()) {
diff --git a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunner.java b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunner.java
index f07213fc..31f027ab 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunner.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunner.java
@@ -11,7 +11,9 @@ import org.jsmart.zerocode.core.di.main.ApplicationMainModule;
 import org.jsmart.zerocode.core.di.module.RuntimeHttpClientModule;
 import org.jsmart.zerocode.core.domain.JsonTestCase;
 import org.jsmart.zerocode.core.domain.JsonTestCases;
+import org.jsmart.zerocode.core.domain.Scenario;
 import org.jsmart.zerocode.core.domain.ScenarioSpec;
+import org.jsmart.zerocode.core.domain.Scenarios;
 import org.jsmart.zerocode.core.domain.TargetEnv;
 import org.jsmart.zerocode.core.domain.TestPackageRoot;
 import org.jsmart.zerocode.core.domain.UseHttpClient;
@@ -76,7 +78,8 @@ public class ZeroCodePackageRunner extends ParentRunner<ScenarioSpec> {
     protected List<ScenarioSpec> getChildren() {
         TestPackageRoot rootPackageAnnotation = testClass.getAnnotation(TestPackageRoot.class);
         JsonTestCases jsonTestCasesAnnotation = testClass.getAnnotation(JsonTestCases.class);
-        validateSuiteAnnotationPresent(rootPackageAnnotation, jsonTestCasesAnnotation);
+        Scenarios scenariosAnnotation = testClass.getAnnotation(Scenarios.class);
+        validateSuiteAnnotationPresent(rootPackageAnnotation, jsonTestCasesAnnotation, scenariosAnnotation);
 
         if (rootPackageAnnotation != null) {
             /*
@@ -87,10 +90,7 @@ public class ZeroCodePackageRunner extends ParentRunner<ScenarioSpec> {
             return smartUtils.getScenarioSpecListByPackage(rootPackageAnnotation.value());
 
         } else {
-            List<JsonTestCase> jsonTestCases = Arrays.asList(testClass.getAnnotationsByType(JsonTestCase.class));
-            List<String> allEndPointFiles = jsonTestCases.stream()
-                    .map(thisTestCase -> thisTestCase.value())
-                    .collect(Collectors.toList());
+            List<String> allEndPointFiles = readTestScenarioFiles();
 
             return allEndPointFiles.stream()
                     .map(testResource -> {
@@ -241,18 +241,43 @@ public class ZeroCodePackageRunner extends ParentRunner<ScenarioSpec> {
         }
     }
 
+    private List<String> readTestScenarioFiles() {
+        // --------------------------------------------------
+        // Backward compatibility
+        // Warning - Stop supporting this for future releases
+        // i.e. JsonTestCase
+        // --------------------------------------------------
+        List<JsonTestCase> jsonTestCases = Arrays.asList(testClass.getAnnotationsByType(JsonTestCase.class));
+        if(jsonTestCases != null && jsonTestCases.size() > 0){
+            return jsonTestCases.stream()
+                    .map(thisTestCase -> thisTestCase.value())
+                    .collect(Collectors.toList());
+        }
+
+        List<Scenario> scenarios = Arrays.asList(testClass.getAnnotationsByType(Scenario.class));
+        return scenarios.stream()
+                .map(thisTestCase -> thisTestCase.value())
+                .collect(Collectors.toList());
+    }
 
-    private void validateSuiteAnnotationPresent(TestPackageRoot rootPackageAnnotation, JsonTestCases jsonTestCasesAnnotation) {
-        if (rootPackageAnnotation == null && jsonTestCasesAnnotation == null) {
+    private void validateSuiteAnnotationPresent(TestPackageRoot rootPackageAnnotation,
+                                                JsonTestCases jsonTestCasesAnnotation,
+                                                Scenarios scenarios) {
+        if (rootPackageAnnotation == null && (jsonTestCasesAnnotation == null && scenarios == null)) {
             throw new RuntimeException("Missing Test Suite details." +
                     "To run as a Test Suite - \n" +
-                    "Annotate your Test Suite class with, e.g. \n@TestPackageRoot(\"resource_folder_for_test_cases\") " +
-                    "\n-Or- \n" +
+                    "Annotate your Test Suite class with, e.g. \n@TestPackageRoot(\"resource_folder_for_scenario_files\") " +
+                    "\n\n-Or- \n" +
                     "Annotate your Test Suite class with, e.g. \n@JsonTestCases({\n" +
                     "        @JsonTestCase(\"path/to/test_case_1.json\"),\n" +
                     "        @JsonTestCase(\"path/to/test_case_2.json\")\n" +
                     "})" +
-                    "\n-Or- \n" +
+                    "\n\n-Or- \n" +
+                    "Annotate your Test Suite class with, e.g. \n@Scenarios({\n" +
+                    "        @Scenario(\"path/to/test_case_1.json\"),\n" +
+                    "        @Scenario(\"path/to/test_case_2.json\")\n" +
+                    "})" +
+                    "\n\n-Or- \n" +
                     "Run as usual 'Junit Suite' pointing to the individual test classes.");
         }
     }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
index 0d860c6e..3ca94431 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/runner/ZeroCodeUnitRunner.java
@@ -3,10 +3,21 @@ package org.jsmart.zerocode.core.runner;
 import com.google.inject.Guice;
 import com.google.inject.Injector;
 import com.google.inject.util.Modules;
+import java.lang.annotation.Annotation;
+import java.time.LocalDateTime;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.stream.Collectors;
 import org.jsmart.zerocode.core.di.main.ApplicationMainModule;
 import org.jsmart.zerocode.core.di.module.RuntimeHttpClientModule;
 import org.jsmart.zerocode.core.di.module.RuntimeKafkaClientModule;
-import org.jsmart.zerocode.core.domain.*;
+import org.jsmart.zerocode.core.domain.HostProperties;
+import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.Scenario;
+import org.jsmart.zerocode.core.domain.ScenarioSpec;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.domain.UseHttpClient;
+import org.jsmart.zerocode.core.domain.UseKafkaClient;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeExecResultBuilder;
 import org.jsmart.zerocode.core.domain.builders.ZeroCodeExecResultIoWriteBuilder;
 import org.jsmart.zerocode.core.engine.listener.ZeroCodeTestReportListener;
@@ -30,11 +41,6 @@ import org.junit.runners.model.Statement;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
-import java.time.LocalDateTime;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.stream.Collectors;
-
 import static java.lang.System.getProperty;
 import static org.jsmart.zerocode.core.domain.builders.ZeroCodeExecResultBuilder.newInstance;
 import static org.jsmart.zerocode.core.domain.reports.ZeroCodeReportProperties.CHARTS_AND_CSV;
@@ -106,15 +112,18 @@ public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
     protected void runChild(FrameworkMethod method, RunNotifier notifier) {
 
         final Description description = describeChild(method);
-        JsonTestCase annotation = method.getMethod().getAnnotation(JsonTestCase.class);
+        JsonTestCase jsonTestCaseAnno = method.getMethod().getAnnotation(JsonTestCase.class);
+        if(jsonTestCaseAnno == null){
+            jsonTestCaseAnno = evalScenarioToJsonTestCase(method.getMethod().getAnnotation(Scenario.class));
+        }
 
         if (isIgnored(method)) {
 
             notifier.fireTestIgnored(description);
 
-        } else if (annotation != null) {
+        } else if (jsonTestCaseAnno != null) {
 
-            runLeafJsonTest(notifier, description, annotation);
+            runLeafJsonTest(notifier, description, jsonTestCaseAnno);
 
         } else {
             // =-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=-=
@@ -179,9 +188,9 @@ public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
         return getMainModuleInjector().getInstance(ZeroCodeReportGenerator.class);
     }
 
-    private void runLeafJsonTest(RunNotifier notifier, Description description, JsonTestCase annotation) {
-        if (annotation != null) {
-            currentTestCase = annotation.value();
+    private void runLeafJsonTest(RunNotifier notifier, Description description, JsonTestCase jsonTestCaseAnno) {
+        if (jsonTestCaseAnno != null) {
+            currentTestCase = jsonTestCaseAnno.value();
         }
 
         notifier.fireTestStarted(description);
@@ -218,9 +227,14 @@ public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
         List<FrameworkMethod> children = getChildren();
         children.forEach(
                 frameworkMethod -> {
-                    JsonTestCase annotation = frameworkMethod.getAnnotation(JsonTestCase.class);
-                    if (annotation != null) {
-                        smartTestCaseNames.add(annotation.value());
+                    JsonTestCase jsonTestCaseAnno = frameworkMethod.getAnnotation(JsonTestCase.class);
+
+                    if(jsonTestCaseAnno == null){
+                        jsonTestCaseAnno = evalScenarioToJsonTestCase(frameworkMethod.getAnnotation(Scenario.class));
+                    }
+
+                    if (jsonTestCaseAnno != null) {
+                        smartTestCaseNames.add(jsonTestCaseAnno.value());
                     } else {
                         smartTestCaseNames.add(frameworkMethod.getName());
                     }
@@ -331,4 +345,25 @@ public class ZeroCodeUnitRunner extends BlockJUnit4ClassRunner {
             reportListener.testRunFinished(new Result());
         }
     }
+
+    private JsonTestCase evalScenarioToJsonTestCase(Scenario scenario) {
+        // ---------------------------------------------------
+        // If Scenario is present then convert to JsonTestCase
+        // ---------------------------------------------------
+        JsonTestCase jsonTestCase = new JsonTestCase() {
+
+            @Override
+            public Class<? extends Annotation> annotationType() {
+                return JsonTestCase.class;
+            }
+
+            @Override
+            public String value() {
+                return scenario != null? scenario.value(): null;
+            }
+        };
+
+        return jsonTestCase.value() == null ? null : jsonTestCase;
+    }
+
 }


Test patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java
index ea36d8ef..6da90a2c 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesor.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (C) 2014 jApps Ltd and
- * Copyright 2016 the original author or authors.
- *
- * Licensed 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.jsmart.zerocode.core.engine.preprocessor;
 
 import org.jsmart.zerocode.core.engine.assertion.AssertionReport;
@@ -29,9 +13,9 @@ public interface ZeroCodeJsonTestProcesor {
 
     String resolveJsonPaths(String resolvedFromTemplate, String jsonString);
 
-    public List<String> getAllJsonPathTokens(String requestJsonAsString);
+    List<String> getAllJsonPathTokens(String requestJsonAsString);
 
-    List<JsonAsserter> createAssertersFrom(String resolvedAssertionJson);
+    List<JsonAsserter> createJsonAsserters(String resolvedAssertionJson);
 
     List<AssertionReport> assertAllAndReturnFailed(List<JsonAsserter> asserters, String executionResult);
 }
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
index e1e1ced5..52c89889 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImpl.java
@@ -1,19 +1,3 @@
-/*
- * Copyright (C) 2014 jApps Ltd and
- * Copyright 2016 the original author or authors.
- *
- * Licensed 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.jsmart.zerocode.core.engine.preprocessor;
 
 import com.fasterxml.jackson.databind.JsonNode;
@@ -159,8 +143,13 @@ public class ZeroCodeJsonTestProcesorImpl implements ZeroCodeJsonTestProcesor {
         return jsonPaths;
     }
 
+    /**
+     * Use skyscreamer-JSONAssert lib for the below JSON assertions.
+     * Then we stop maintaining these following assertion code.
+     * Raise a Tech-Debt ticket(TODO)
+     */
     @Override
-    public List<JsonAsserter> createAssertersFrom(String resolvedAssertionJson) {
+    public List<JsonAsserter> createJsonAsserters(String resolvedAssertionJson) {
         List<JsonAsserter> asserters = new ArrayList<>();
         try {
             JsonNode jsonNode = mapper.readTree(resolvedAssertionJson);
diff --git a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
index 2c6be922..8bec24ba 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeJsonTestProcesorImplTest.java
@@ -157,7 +157,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         // start assertion
         String sapmleExecutionResult =
                 smartUtils.getJsonDocumentAsString("09_test_engine/02_2_sample_resolved_execution_response.json");
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(17));
 
         List<AssertionReport> failedReports = jsonPreProcessor.assertAllAndReturnFailed(asserters, sapmleExecutionResult);
@@ -204,7 +204,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         assertThat(resolvedAssertions, containsString("\"id-generated-0101\""));
 
         // start assertion
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(1));
 
         String sampleExecutionResult = "\"id-generated-0101-XY\"";
@@ -239,7 +239,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         assertThat(resolvedAssertions, containsString("1099"));
 
         // start assertion
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(1));
 
         Integer sampleExecutionResult = 1077;
@@ -311,7 +311,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"name\":\"$CONTAINS.STRING.IGNORECASE:CReASY\"}}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -336,7 +336,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"name\":\"$CONTAINS.STRING.IGNORECASE:CReASY\"}}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -362,7 +362,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"dob\":\"$MATCHES.STRING:\\\\d{4}-\\\\d{2}-\\\\d{2}\"}}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -388,7 +388,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":2}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -421,7 +421,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":2}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -451,7 +451,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$GT.1\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -484,7 +484,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$GT.5\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -519,7 +519,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$LT.3\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -552,7 +552,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$LT.1\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -587,7 +587,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$EQ.2\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -620,7 +620,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$EQ.3\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -655,7 +655,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$NOT.EQ.3\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -688,7 +688,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("{\"persons.SIZE\":\"$NOT.EQ.2\"}"));
 
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -724,7 +724,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         assertThat(resolvedAssertions, containsString("\"startDateTime\":\"$LOCAL.DATETIME.BEFORE:2015-09-14T09:49:34.000Z\","));
         assertThat(resolvedAssertions, containsString("\"endDateTime\":\"$LOCAL.DATETIME.AFTER:2015-09-14T09:49:34.000Z\""));
         
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(3));
 
         String mockTestResponse = "{\n" +
@@ -755,7 +755,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         assertThat(resolvedAssertions, containsString("\"startDateTime\":\"$LOCAL.DATETIME.BEFORE:2016-09-14T09:49:34.000Z\","));
         assertThat(resolvedAssertions, containsString("\"endDateTime\":\"$LOCAL.DATETIME.AFTER:2019-09-14T09:49:34.000Z\""));
         
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(3));
 
         String mockTestResponse = "{\n" +
@@ -792,7 +792,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("\"startDateTime\":\"$LOCAL.DATETIME.AFTER:2015-09-14T09:49:34.000Z\""));
         
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
@@ -825,7 +825,7 @@ public class ZeroCodeJsonTestProcesorImplTest {
         final String resolvedAssertions = jsonPreProcessor.resolveStringJson(assertionsSectionAsString, mockScenarioState);
         assertThat(resolvedAssertions, containsString("\"startDateTime\":\"$LOCAL.DATETIME.BEFORE:2015-09-14T09:49:34.000Z\""));
         
-        List<JsonAsserter> asserters = jsonPreProcessor.createAssertersFrom(resolvedAssertions);
+        List<JsonAsserter> asserters = jsonPreProcessor.createJsonAsserters(resolvedAssertions);
         assertThat(asserters.size(), is(2));
 
         String mockTestResponse = "{\n" +
diff --git a/core/src/test/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunnerScenariosTest.java b/core/src/test/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunnerScenariosTest.java
new file mode 100644
index 00000000..3a338c24
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/core/runner/ZeroCodePackageRunnerScenariosTest.java
@@ -0,0 +1,50 @@
+package org.jsmart.zerocode.core.runner;
+
+import java.util.List;
+import org.jsmart.zerocode.core.domain.Scenario;
+import org.jsmart.zerocode.core.domain.ScenarioSpec;
+import org.jsmart.zerocode.core.domain.Scenarios;
+import org.jsmart.zerocode.core.domain.TestPackageRoot;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.Description;
+
+import static org.hamcrest.CoreMatchers.containsString;
+import static org.hamcrest.CoreMatchers.is;
+import static org.hamcrest.MatcherAssert.assertThat;
+
+public class ZeroCodePackageRunnerScenariosTest {
+
+    ZeroCodePackageRunner zeroCodePackageRunner;
+
+    @Scenarios({
+            @Scenario("unit_tests/folder_a/test_case_1.json"), //any valid path
+            @Scenario("unit_tests/folder_b/test_case_2.json"), //any valid path
+    })
+    public static class ScenarioTestFlowExampleSelectedTest {
+    }
+
+    @TestPackageRoot("03_test_one_multi_steps")
+    public static class ScenarioTestFlowSelectedExampleTest {
+    }
+
+    @Before
+    public void initializeRunner() throws Exception {
+        zeroCodePackageRunner = new ZeroCodePackageRunner(ScenarioTestFlowExampleSelectedTest.class);
+    }
+
+    @Test
+    public void willHaveListOf_TestCases_Here() throws Exception {
+        List<ScenarioSpec> children = zeroCodePackageRunner.getChildren();
+        assertThat(children.size(), is(2));
+    }
+
+    @Test
+    public void testDescribeAChild() throws Exception {
+        List<ScenarioSpec> children = zeroCodePackageRunner.getChildren();
+        Description childDescription = zeroCodePackageRunner.describeChild(children.get(0));
+
+        assertThat(childDescription.getDisplayName(), containsString("test scenario 1"));
+    }
+
+}
diff --git a/core/src/test/java/org/jsmart/zerocode/core/scenario/ScenarioAnnotationTest.java b/core/src/test/java/org/jsmart/zerocode/core/scenario/ScenarioAnnotationTest.java
new file mode 100644
index 00000000..d6177d4f
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/core/scenario/ScenarioAnnotationTest.java
@@ -0,0 +1,19 @@
+package org.jsmart.zerocode.core.scenario;
+
+import org.jsmart.zerocode.core.domain.Scenario;
+import org.jsmart.zerocode.core.domain.TargetEnv;
+import org.jsmart.zerocode.core.tests.customrunner.TestOnlyZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@TargetEnv("config_hosts.properties")
+@RunWith(TestOnlyZeroCodeUnitRunner.class)
+public class ScenarioAnnotationTest {
+
+    @Test
+    @Scenario("01_verification_test_cases/05_number_equals_test.json")
+    public void willPassIfEqualsToSame_number() throws Exception {
+
+    }
+}
+
diff --git a/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworld/JustHelloWorldTest.java b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworld/JustHelloWorldTest.java
index 8c9fc64f..12046e8e 100644
--- a/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworld/JustHelloWorldTest.java
+++ b/http-testing/src/test/java/org/jsmart/zerocode/testhelp/tests/helloworld/JustHelloWorldTest.java
@@ -1,6 +1,6 @@
 package org.jsmart.zerocode.testhelp.tests.helloworld;
 
-import org.jsmart.zerocode.core.domain.JsonTestCase;
+import org.jsmart.zerocode.core.domain.Scenario;
 import org.jsmart.zerocode.core.domain.TargetEnv;
 import org.jsmart.zerocode.core.runner.ZeroCodeUnitRunner;
 import org.junit.Test;
@@ -11,7 +11,7 @@ import org.junit.runner.RunWith;
 public class JustHelloWorldTest {
 
     @Test
-    @JsonTestCase("helloworld/hello_world_status_ok_assertions.json")
+    @Scenario("helloworld/hello_world_status_ok_assertions.json")
     public void testGet() throws Exception {
     }