Repository: authorjapps/zerocode
Pull request #430 (2020-09-10 20:32:27)

Custom assert #429
# <Feature Title>

PR Branch
**_#ADD LINK TO THE PR BRANCH_**

## Motivation and Context

## Checklist:

* [x] Unit tests added

* [x] Integration tests added

* [x] Test names are meaningful

* [x] Feature manually tested

* [x] Branch build passed

* [ ] No 'package.*' in the imports

* [ ] Relevant Wiki page updated with clear instruction for the end user
  * [ ] Not applicable. This was only a refactor change, no functional or behaviour changes were introduced

* [ ] Http test added to `http-testing` module(if applicable) ?
  * [x] Not applicable. The changes did not affect HTTP automation flow

* [ ] Kafka test added to `kafka-testing` module(if applicable) ?
  * [x] Not applicable. The changes did not affect Kafka automation flow



Patch:
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/assertion/field/FieldMatchesCustomAsserter.java b/core/src/main/java/org/jsmart/zerocode/core/engine/assertion/field/FieldMatchesCustomAsserter.java
new file mode 100644
index 00000000..32bced61
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/assertion/field/FieldMatchesCustomAsserter.java
@@ -0,0 +1,41 @@
+
+package org.jsmart.zerocode.core.engine.assertion.field;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
+import org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher;
+import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;
+import org.jsmart.zerocode.core.engine.executor.javaapi.JavaCustomExecutor;
+
+import static org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher.aMatchingMessage;
+import static org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher.aNotMatchingMessage;
+
+public class FieldMatchesCustomAsserter implements JsonAsserter {
+    private final String path;
+    private final String expected;
+    ObjectMapper mapper = new ObjectMapperProvider().get();
+
+    public FieldMatchesCustomAsserter(String path, String expected) {
+        this.path = path;
+        this.expected = expected;
+    }
+
+    @Override
+    public String getPath() {
+        return path;
+    }
+
+    @Override
+    public Object getExpected() {
+        return expected;
+    }
+
+    @Override
+    public FieldAssertionMatcher actualEqualsToExpected(Object actual) {
+        boolean areEqual = JavaCustomExecutor.executeMethod(expected, actual);
+
+        return areEqual ?
+                aMatchingMessage() :
+                aNotMatchingMessage(path, " custom assertion:" + expected, actual);
+    }
+}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/executor/javaapi/CustomAsserter.java b/core/src/main/java/org/jsmart/zerocode/core/engine/executor/javaapi/CustomAsserter.java
new file mode 100644
index 00000000..390e4125
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/executor/javaapi/CustomAsserter.java
@@ -0,0 +1,7 @@
+package org.jsmart.zerocode.core.engine.executor.javaapi;
+
+import java.util.Map;
+
+public interface CustomAsserter {
+    Boolean asserted(Map<String, Object> inputParamMap, Object actualFieldValue);
+}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/executor/javaapi/JavaCustomExecutor.java b/core/src/main/java/org/jsmart/zerocode/core/engine/executor/javaapi/JavaCustomExecutor.java
new file mode 100644
index 00000000..7b7930e3
--- /dev/null
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/executor/javaapi/JavaCustomExecutor.java
@@ -0,0 +1,51 @@
+package org.jsmart.zerocode.core.engine.executor.javaapi;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
+
+import java.lang.reflect.Method;
+import java.util.HashMap;
+import java.util.Map;
+
+public class JavaCustomExecutor {
+
+    public static Boolean executeMethod(String fqMethodNameWithRawParams, Object actualFieldValue) {
+        ObjectMapper mapper = new ObjectMapperProvider().get();
+        try {
+            // -------------------
+            // Find the class name
+            // -------------------
+            String[] parts = fqMethodNameWithRawParams.split("#");
+            String className = parts[0];
+
+            // -------------------
+            // Find the method name
+            // -------------------
+            String methodNameWithVal = parts[1];
+            String[] methodParts = methodNameWithVal.split(":", 2);
+            String methodName = methodParts[0];
+
+            // ---------------------
+            // Find method arguments
+            // ---------------------
+            String expectedRawJsonArgs = methodParts[1];
+            HashMap<String, Object> valueMap = mapper.readValue(expectedRawJsonArgs, HashMap.class);
+
+            // -------------------
+            // Invoke
+            // -------------------
+            Class<?> clazz = Class.forName(className);
+            Method method = clazz.getMethod(methodName, Map.class, Object.class);
+            // ----------------------------------------------------
+            // For static method exec, invoke(clazz, param1, ...);
+            // clazz.newInstance() not required
+            // ----------------------------------------------------
+            Object result = method.invoke(clazz.newInstance(), valueMap, actualFieldValue);
+
+            return (Boolean) result;
+
+        } catch (Exception e) {
+            throw new RuntimeException(e);
+        }
+    }
+}
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeAssertionsProcessorImpl.java b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeAssertionsProcessorImpl.java
index 4f32907a..2f68c433 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeAssertionsProcessorImpl.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/preprocessor/ZeroCodeAssertionsProcessorImpl.java
@@ -24,42 +24,13 @@ import org.jsmart.zerocode.core.engine.assertion.FieldAssertionMatcher;
 import org.jsmart.zerocode.core.engine.assertion.JsonAsserter;
 import org.jsmart.zerocode.core.engine.assertion.array.ArrayIsEmptyAsserterImpl;
 import org.jsmart.zerocode.core.engine.assertion.array.ArraySizeAsserterImpl;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldContainsStringAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldContainsStringIgnoreCaseAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasDateAfterValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasDateBeforeValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasEqualNumberValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasExactValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasGreaterThanValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasInEqualNumberValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldHasLesserThanValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldIsNotNullAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldIsNullAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldIsOneOfValueAsserter;
-import org.jsmart.zerocode.core.engine.assertion.field.FieldMatchesRegexPatternAsserter;
+import org.jsmart.zerocode.core.engine.assertion.field.*;
 
 import static java.lang.Integer.valueOf;
 import static java.lang.String.format;
 import static org.apache.commons.lang.StringEscapeUtils.escapeJava;
 import static org.apache.commons.lang.StringUtils.substringBetween;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_LOCAL_DATETIME_AFTER;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_LOCAL_DATETIME_BEFORE;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_PATH_SIZE;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_CONTAINS_STRING;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_CONTAINS_STRING_IGNORE_CASE;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_EMPTY_ARRAY;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_EQUAL_TO_NUMBER;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_GREATER_THAN;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_IS_NOT_NULL;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_IS_NULL;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_IS_ONE_OF;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_LESSER_THAN;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_MATCHES_STRING;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_NOT_EQUAL_TO_NUMBER;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_NOT_NULL;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_NULL;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.ASSERT_VALUE_ONE_OF;
-import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.RAW_BODY;
+import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeAssertionTokens.*;
 import static org.jsmart.zerocode.core.engine.tokens.ZeroCodeValueTokens.$VALUE;
 import static org.jsmart.zerocode.core.utils.FieldTypeConversionUtils.digTypeCast;
 import static org.jsmart.zerocode.core.utils.FieldTypeConversionUtils.fieldTypes;
@@ -192,10 +163,17 @@ public class ZeroCodeAssertionsProcessorImpl implements ZeroCodeAssertionsProces
                 JsonAsserter asserter;
                 if (ASSERT_VALUE_NOT_NULL.equals(value) || ASSERT_VALUE_IS_NOT_NULL.equals(value)) {
                     asserter = new FieldIsNotNullAsserter(path);
+
+                } else if (value instanceof String && ((String) value).startsWith(ASSERT_VALUE_CUSTOM_ASSERT)) {
+                    String expected = ((String) value).substring(ASSERT_VALUE_CUSTOM_ASSERT.length());
+                    asserter = new FieldMatchesCustomAsserter(path, expected);
+
                 } else if (ASSERT_VALUE_NULL.equals(value) || ASSERT_VALUE_IS_NULL.equals(value)) {
                     asserter = new FieldIsNullAsserter(path);
+
                 } else if (ASSERT_VALUE_EMPTY_ARRAY.equals(value)) {
                     asserter = new ArrayIsEmptyAsserterImpl(path);
+
                 } else if (path.endsWith(ASSERT_PATH_SIZE)) {
                     path = path.substring(0, path.length() - ASSERT_PATH_SIZE.length());
                     if (value instanceof Number) {
diff --git a/core/src/main/java/org/jsmart/zerocode/core/engine/tokens/ZeroCodeAssertionTokens.java b/core/src/main/java/org/jsmart/zerocode/core/engine/tokens/ZeroCodeAssertionTokens.java
index 659339ad..119a4961 100644
--- a/core/src/main/java/org/jsmart/zerocode/core/engine/tokens/ZeroCodeAssertionTokens.java
+++ b/core/src/main/java/org/jsmart/zerocode/core/engine/tokens/ZeroCodeAssertionTokens.java
@@ -15,6 +15,7 @@ public class ZeroCodeAssertionTokens {
     public static final String ASSERT_VALUE_NOT_NULL = "$NOT.NULL";
     public static final String ASSERT_VALUE_IS_NULL = "$IS.NULL";
     public static final String ASSERT_VALUE_NULL = "$NULL";
+    public static final String ASSERT_VALUE_CUSTOM_ASSERT = "$CUSTOM.ASSERT:";
     public static final String ASSERT_VALUE_EMPTY_ARRAY = "$[]";
     public static final String ASSERT_PATH_SIZE = ".SIZE";
     public static final String ASSERT_VALUE_CONTAINS_STRING_IGNORE_CASE = "$CONTAINS.STRING.IGNORECASE:";


Test patch:
diff --git a/core/src/test/java/org/jsmart/zerocode/core/engine/executor/javaapi/JavaCustomExecutorTest.java b/core/src/test/java/org/jsmart/zerocode/core/engine/executor/javaapi/JavaCustomExecutorTest.java
new file mode 100644
index 00000000..351ff8ef
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/core/engine/executor/javaapi/JavaCustomExecutorTest.java
@@ -0,0 +1,93 @@
+package org.jsmart.zerocode.core.engine.executor.javaapi;
+
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.jsmart.zerocode.core.di.provider.ObjectMapperProvider;
+import org.junit.Test;
+
+import java.util.HashMap;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+
+public class JavaCustomExecutorTest {
+
+    @Test
+    public void testSplit() {
+        String qualifiedMethod = "org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils#strLen:4";
+        String[] parts = qualifiedMethod.split("#");
+        String className = parts[0];
+        assertThat(className, is("org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils"));
+
+        String methodNameWithVal = parts[1];
+        String[] methodParts = methodNameWithVal.split(":");
+        String methodName = methodParts[0];
+        assertThat(methodName, is("strLen"));
+
+        String argsWithComma = methodParts[1];
+        String[] argsParts = argsWithComma.split(",");
+        assertThat(argsParts.length, is(1));
+    }
+
+    @Test
+    public void testSplitArgs() {
+        String qualifiedMethod = "org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils#strLen:4,5";
+        String[] parts = qualifiedMethod.split("#");
+        String className = parts[0];
+        assertThat(className, is("org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils"));
+
+        String methodNameWithVal = parts[1];
+        String[] methodParts = methodNameWithVal.split(":");
+        String methodName = methodParts[0];
+        assertThat(methodName, is("strLen"));
+
+        String argsWithComma = methodParts[1];
+        String[] argsParts = argsWithComma.split(",");
+        assertThat(argsParts.length, is(2));
+    }
+
+    @Test
+    public void testSplitArgsString() {
+        String qualifiedMethod = "org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils#strLen:Foo,Bar";
+        String[] parts = qualifiedMethod.split("#");
+        String className = parts[0];
+        assertThat(className, is("org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils"));
+
+        String methodNameWithVal = parts[1];
+        String[] methodParts = methodNameWithVal.split(":");
+        String methodName = methodParts[0];
+        assertThat(methodName, is("strLen"));
+
+        String argsWithComma = methodParts[1];
+        String[] argsParts = argsWithComma.split(",");
+        assertThat(argsParts.length, is(2));
+    }
+
+    @Test
+    public void testSplitArgsAsJson() throws JsonProcessingException {
+        String qualifiedMethod = "org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils#strLen:{\"expectLen\":5, \"expFlag\":true}";
+        String[] parts = qualifiedMethod.split("#");
+        String className = parts[0];
+        assertThat(className, is("org.jsmart.zerocode.core.engine.executor.javaapi.CustomUtils"));
+
+        String methodNameWithVal = parts[1];
+        String[] methodParts = methodNameWithVal.split(":", 2);
+        String methodName = methodParts[0];
+        String expectedRawJson = methodParts[1];
+        assertThat(methodName, is("strLen"));
+        assertThat(expectedRawJson, is("{\"expectLen\":5, \"expFlag\":true}"));
+
+        ObjectMapper mapper = new ObjectMapperProvider().get();
+        HashMap<String, Object> valueMap = mapper.readValue(expectedRawJson, HashMap.class);
+        assertThat(valueMap.get("expectLen"), is(5));
+        assertThat(valueMap.get("expFlag"), is(true));
+    }
+
+    @Test
+    public void testExecuteByReflection() throws JsonProcessingException {
+        String qualifiedMethod = "org.jsmart.zerocode.integrationtests.customassert.MyCustomComparator#assertLength:{\"expectLen\":3}";
+        Boolean passed = JavaCustomExecutor.executeMethod(qualifiedMethod, "Foo");
+        assertThat(passed, is(true));
+    }
+
+}
\ No newline at end of file
diff --git a/core/src/test/java/org/jsmart/zerocode/core/verification/queryparams/QueryParamVerifyTest.java b/core/src/test/java/org/jsmart/zerocode/core/verification/queryparams/QueryParamVerifyTest.java
index b53667f8..dde6afcf 100644
--- a/core/src/test/java/org/jsmart/zerocode/core/verification/queryparams/QueryParamVerifyTest.java
+++ b/core/src/test/java/org/jsmart/zerocode/core/verification/queryparams/QueryParamVerifyTest.java
@@ -9,7 +9,7 @@ import org.junit.runner.RunWith;
 @HostProperties(host="http://localhost", port=9998, context = "")
 @RunWith(TestOnlyZeroCodeUnitRunner.class)
 public class QueryParamVerifyTest {
-    
+
     /**
      * Mock end points are in test/resources: simulators/test_purpose_end_points.json
      */
@@ -17,7 +17,7 @@ public class QueryParamVerifyTest {
     @Test
     @JsonTestCase("integration_test_files/query_params/request_with_query_paramas_map_test.json")
     public void testQueryParamsAsMap() throws Exception {
-    
+
     }
 
 }
diff --git a/core/src/test/java/org/jsmart/zerocode/integrationtests/CustomAssertionTest.java b/core/src/test/java/org/jsmart/zerocode/integrationtests/CustomAssertionTest.java
new file mode 100644
index 00000000..6e95e356
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/integrationtests/CustomAssertionTest.java
@@ -0,0 +1,26 @@
+package org.jsmart.zerocode.integrationtests;
+
+import org.jsmart.zerocode.core.domain.HostProperties;
+import org.jsmart.zerocode.core.domain.Scenario;
+import org.jsmart.zerocode.core.tests.customrunner.TestOnlyZeroCodeUnitRunner;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@HostProperties(host="http://localhost", port=9998, context = "")
+@RunWith(TestOnlyZeroCodeUnitRunner.class)
+public class CustomAssertionTest {
+    
+    /**
+     * Mock end points are in test/resources: simulators/test_purpose_end_points.json
+     */
+
+    @Test
+    @Scenario("integration_test_files/custom_assert/execute_java_method_as_custom_assertions.json")
+    public void testQueryParamsAsMap() throws Exception {
+    
+    }
+
+}
+
+
+
diff --git a/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparator.java b/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparator.java
new file mode 100644
index 00000000..ae4e0489
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparator.java
@@ -0,0 +1,57 @@
+package org.jsmart.zerocode.integrationtests.customassert;
+
+import org.jsmart.zerocode.core.engine.executor.javaapi.CustomAsserter;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+
+import java.util.Map;
+
+/**
+ * implement CustomAsserter interface method asserted(...)
+ * or
+ * implement your own flavoured method and pass it as below to the DSL:
+ * e.g.
+ * 1)
+ * DSL: "key": "$CUSTOM.ASSERT:org.pkg...MyCustomComparator#myMethod:{\"expectDate\":\"2020-09-20\"}",
+ * Java: public Boolean dateBetween(Map<String, Object> inputParamMap, Object actualDate) {...}
+ * <p>
+ * 2)
+ * DSL: "actualDate": "$CUSTOM.ASSERT:org.pkg...MyCustomComparator#dateBetween:{\"fromDate\":\"2020-09-20\", \"toDate\":\"2021-09-20\"}",
+ * Java: public Boolean dateBetween(Map<String, Object> inputParamMap, Object actualDate) {...}
+ */
+public class MyCustomComparator implements CustomAsserter {
+    private static final Logger LOGGER = LoggerFactory.getLogger(MyCustomComparator.class);
+
+    // ---------------------------
+    // "public static" also good
+    // ---------------------------
+    public Boolean asserted(Map<String, Object> inputParamMap, Object actualFieldValue) {
+        int expectLen = Integer.parseInt(inputParamMap.get("expectLen").toString());
+        return expectLen == actualFieldValue.toString().length();
+    }
+
+    public Boolean assertLength(Map<String, Object> inputParamMap, Object actualFieldValue) {
+        int expectLen = Integer.parseInt(inputParamMap.get("expectLen").toString());
+        int actualLength = actualFieldValue.toString().length();
+        boolean success = (expectLen == actualLength);
+        if (!success) {
+            LOGGER.error("\n" +
+                            "\t|\n" +
+                            "\t|\n" +
+                            "\t+---assertion error --> Actual length of {}}={} did not match expected length of {} \n" +
+                            "\t|\n" +
+                            "\t|\n",
+                    actualFieldValue, actualLength, expectLen);
+        }
+        return success;
+    }
+
+    public static Integer strLen(String input) {
+        return 6;
+    }
+
+    public static Integer strLen(String input1, String inut2) {
+        return 7;
+    }
+
+}
diff --git a/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorReflectionTest.java b/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorReflectionTest.java
new file mode 100644
index 00000000..ff917f83
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorReflectionTest.java
@@ -0,0 +1,6 @@
+package org.jsmart.zerocode.integrationtests.customassert;
+
+public class MyCustomComparatorReflectionTest {
+    // See tests here:
+    // src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorTest.java
+}
diff --git a/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorTest.java b/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorTest.java
new file mode 100644
index 00000000..ac46866c
--- /dev/null
+++ b/core/src/test/java/org/jsmart/zerocode/integrationtests/customassert/MyCustomComparatorTest.java
@@ -0,0 +1,45 @@
+package org.jsmart.zerocode.integrationtests.customassert;
+
+import org.junit.Test;
+
+import static org.hamcrest.MatcherAssert.assertThat;
+import static org.hamcrest.core.Is.is;
+import static org.hamcrest.core.IsNull.nullValue;
+
+public class MyCustomComparatorTest {
+    @Test
+    public void test_reflection_oneParam() throws Exception {
+        java.lang.reflect.Method method;
+        Object result;
+        Class<?> clazz;
+        clazz = Class.forName("org.jsmart.zerocode.integrationtests.customassert.MyCustomComparator");
+
+        method = clazz.getMethod("strLen", String.class);
+        result = method.invoke(MyCustomComparator.class, "Hello");
+        assertThat(result, is(6));
+    }
+
+    @Test
+    public void test_reflection_twoParams() throws Exception {
+        java.lang.reflect.Method method;
+        Object result;
+        Class<?> clazz;
+        clazz = Class.forName("org.jsmart.zerocode.integrationtests.customassert.MyCustomComparator");
+
+        method = clazz.getMethod("strLen", String.class, String.class);
+        result = method.invoke(MyCustomComparator.class, "Hello", "Hello2");
+        assertThat(result, is(7));
+    }
+
+    @Test
+    public void test_reflection_longParam() throws Exception {
+        java.lang.reflect.Method method;
+        Object result;
+        Class<?> clazz;
+
+        clazz = Class.forName("java.lang.Thread");
+        method = clazz.getMethod("sleep", long.class);
+        result = method.invoke(Thread.class, 2000L);
+        assertThat(result, nullValue());
+    }
+}
diff --git a/core/src/test/resources/integration_test_files/custom_assert/execute_java_method_as_custom_assertions.json b/core/src/test/resources/integration_test_files/custom_assert/execute_java_method_as_custom_assertions.json
new file mode 100644
index 00000000..c0622b22
--- /dev/null
+++ b/core/src/test/resources/integration_test_files/custom_assert/execute_java_method_as_custom_assertions.json
@@ -0,0 +1,25 @@
+{
+    "scenarioName": "User a custom asserter to assert a field value @Chakru #Fidelity",
+    "steps": [
+        {
+            "name": "find_match",
+            "url": "/api/v1/search/persons",
+            "operation": "GET",
+            "request": {
+                "queryParams": {
+                    "lang": "Amazing",
+                    "city": "Lon"
+                }
+            },
+            "assertions": {
+                "status": 200,
+                "body": {
+                    "exactMatches": true,
+                    "name": "$CUSTOM.ASSERT:org.jsmart.zerocode.integrationtests.customassert.MyCustomComparator#asserted:{\"expectLen\":7}",
+                    "lang": "$CUSTOM.ASSERT:org.jsmart.zerocode.integrationtests.customassert.MyCustomComparator#assertLength:{\"expectLen\":7}",
+                    "city": "Lon"
+                }
+            }
+        }
+    ]
+}
\ No newline at end of file