fckbo
fckbo

Reputation: 167

Cannot use a Citrus variable in a Java function invoked by a Test behavior

I want to loop within a test to implement a behavior that will respond to some requests with messages build from "message templates (files)" in which I replace some strings with the value of a citrus test variable and the index of the loop. I think I managed to almost get it working but unfortunately my test crash when I'm trying to use the ReplaceAll String functions within my behavior. See below the code snippet I wrote in which I remove all the unnecessary parts in order to hopefully make my problem simple to understand

   public class myBehavior extends AbstractTestBehavior {

        private String payloadData;

        myBehavior withPayloadData(String payload) {
            this.payloadData = payload;
            return this;
        }

        @Override
        public void apply() {
            echo("[behavior] - OK ->behavior is invoked");
            echo("[behavior]" + payloadData + " - OK ->variable from Test is correctly transmitted to behavior");
            echo(func_asis(payloadData));
            echo(func_replace(payloadData));  // if you uncomment this line the test will crash at starting time when invoking replace_all
        }


        String func_asis(String myvar)
        {
          String s = "This is a string in which nothing is replaced, OK fine !";
          echo("[func_asis] OK ->in func_asis now ");
          echo("[func_asis] myvar="+ myvar + " - OK ->variable from Test is correctly transmitted to func_asis");
          return s;
        }

        String func_replace(String myvar)
        {
          String s = "This is a string in which to replace !!Name!! by the value of my citrus variable but it crashes";
          echo("[func_replace] OK ->in func_replace");
          echo("[func_replace] myvar="+ myvar + " - OK ->variable from Test is correctly transmitted to func_asis");
          //s=s.replaceAll("!!Name!!",myvar); // This will crash when starting the test (not actually when running it) !!!
          return s;
        }

    }

    @CitrusTest 
    public void mySimpleTest() throws IOException {
      description("Simple Test invoking a behavior which it self will invoke a java function");
      variable("vm", "/dc/vm/folder/vm_basename");

      repeat().until("i = 3")
            .actions(
              sleep(1000L),
              applyBehavior(new myBehavior().withPayloadData("${vm}${i}"))
            ); 
    }
    09:21:22,102 DEBUG port.LoggingReporter| BEFORE TEST SUITE
    09:21:22,102 INFO  port.LoggingReporter| 
    09:21:22,103 INFO  port.LoggingReporter| 
    09:21:22,103 INFO  port.LoggingReporter| BEFORE TEST SUITE: SUCCESS
    09:21:22,103 INFO  port.LoggingReporter| ------------------------------------------------------------------------
    09:21:22,103 INFO  port.LoggingReporter| 
    09:21:22,119 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
    09:21:22,128 INFO  port.LoggingReporter| 
    09:21:22,128 INFO  port.LoggingReporter| ------------------------------------------------------------------------
    09:21:22,128 DEBUG port.LoggingReporter| STARTING TEST CitrusLearning.mySimpleTest <com.grge.citrus.cmptest.stratus>
    09:21:22,128 INFO  port.LoggingReporter| 
    09:21:22,129 DEBUG      citrus.TestCase| Initializing test case
    09:21:22,130 DEBUG  context.TestContext| Setting variable: citrus.test.name with value: 'CitrusLearning.mySimpleTest'
    09:21:22,130 DEBUG  context.TestContext| Setting variable: citrus.test.package with value: 'com.grge.citrus.cmptest.stratus'
    09:21:22,130 DEBUG  context.TestContext| Setting variable: vm with value: '/dc/vm/folder/vm_basename'
    09:21:22,130 DEBUG      citrus.TestCase| Test variables:
    09:21:22,131 DEBUG      citrus.TestCase| citrus.test.name = CitrusLearning.mySimpleTest
    09:21:22,131 DEBUG      citrus.TestCase| citrus.test.package = com.grge.citrus.cmptest.stratus
    09:21:22,131 DEBUG      citrus.TestCase| vm = /dc/vm/folder/vm_basename
    09:21:22,131 INFO  port.LoggingReporter| 
    09:21:22,131 DEBUG port.LoggingReporter| TEST STEP 1/1: repeat
    09:21:22,131 DEBUG port.LoggingReporter| TEST ACTION CONTAINER with 9 embedded actions
    09:21:22,131 DEBUG  context.TestContext| Setting variable: i with value: '1'
    09:21:22,134 INFO   actions.SleepAction| Sleeping 1000 ms
    09:21:23,139 INFO   actions.SleepAction| Returning after 1000 ms
    09:21:23,139 INFO    actions.EchoAction| [behavior] - OK ->behavior is invoked
    09:21:23,139 INFO    actions.EchoAction| [behavior]/dc/vm/folder/vm_basename1 - OK ->variable from Test is correctly transmitted to behavior
    09:21:23,140 INFO    actions.EchoAction| [func_asis] OK ->in func_asis now 
    09:21:23,140 INFO    actions.EchoAction| [func_asis] myvar=/dc/vm/folder/vm_basename1 - OK ->variable from Test is correctly transmitted to func_asis
    09:21:23,140 INFO    actions.EchoAction| This is a string in which nothing is replaced, OK fine !
    09:21:23,140 INFO    actions.EchoAction| [func_replace] OK ->in func_replace
    09:21:23,141 INFO    actions.EchoAction| [func_replace] myvar=/dc/vm/folder/vm_basename1 - OK ->variable from Test is correctly transmitted to func_asis
    09:21:23,141 INFO    actions.EchoAction| This is a string in which to replace !!Name!! by the value of my citrus variable but it crashes
    09:21:23,143 DEBUG leanExpressionParser| Boolean expression 2 = 3 evaluates to false
    09:21:23,143 DEBUG  context.TestContext| Setting variable: i with value: '2'
    09:21:23,143 INFO   actions.SleepAction| Sleeping 1000 ms
    09:21:24,145 INFO   actions.SleepAction| Returning after 1000 ms
    09:21:24,145 INFO    actions.EchoAction| [behavior] - OK ->behavior is invoked
    09:21:24,145 INFO    actions.EchoAction| [behavior]/dc/vm/folder/vm_basename2 - OK ->variable from Test is correctly transmitted to behavior
    09:21:24,145 INFO    actions.EchoAction| [func_asis] OK ->in func_asis now 
    09:21:24,145 INFO    actions.EchoAction| [func_asis] myvar=/dc/vm/folder/vm_basename2 - OK ->variable from Test is correctly transmitted to func_asis
    09:21:24,145 INFO    actions.EchoAction| This is a string in which nothing is replaced, OK fine !
    09:21:24,146 INFO    actions.EchoAction| [func_replace] OK ->in func_replace
    09:21:24,146 INFO    actions.EchoAction| [func_replace] myvar=/dc/vm/folder/vm_basename2 - OK ->variable from Test is correctly transmitted to func_asis
    09:21:24,146 INFO    actions.EchoAction| This is a string in which to replace !!Name!! by the value of my citrus variable but it crashes
    09:21:24,146 DEBUG leanExpressionParser| Boolean expression 3 = 3 evaluates to true
    09:21:24,146 INFO  port.LoggingReporter| 
    09:21:24,147 DEBUG port.LoggingReporter| TEST STEP 1/1 SUCCESS
        09:27:51,525 DEBUG port.LoggingReporter| BEFORE TEST SUITE
        09:27:51,525 INFO  port.LoggingReporter| 
        09:27:51,525 INFO  port.LoggingReporter| 
        09:27:51,525 INFO  port.LoggingReporter| BEFORE TEST SUITE: SUCCESS
        09:27:51,525 INFO  port.LoggingReporter| ------------------------------------------------------------------------
        09:27:51,525 INFO  port.LoggingReporter| 
        09:27:51,542 DEBUG t.TestContextFactory| Created new test context - using global variables: '{}'
        09:27:51,551 INFO  port.LoggingReporter| 
        09:27:51,552 ERROR port.LoggingReporter| TEST FAILED CitrusLearning.mySimpleTest <com.grge.citrus.cmptest.stratus> Nested exception is: 
        java.lang.IllegalArgumentException: No group with name {vm}
            at java.util.regex.Matcher.appendReplacement(Matcher.java:849)
            at java.util.regex.Matcher.replaceAll(Matcher.java:955)
            at java.lang.String.replaceAll(String.java:2223)
            at com.grge.citrus.cmptest.stratus.CitrusLearning$myBehavior.func_replace(CitrusLearning.java:180)
            at com.grge.citrus.cmptest.stratus.CitrusLearning$myBehavior.apply(CitrusLearning.java:163)
            at com.consol.citrus.dsl.design.AbstractTestBehavior.apply(AbstractTestBehavior.java:53)
            at com.consol.citrus.dsl.design.ApplyTestBehaviorAction.doExecute(ApplyTestBehaviorAction.java:38)
            at com.consol.citrus.actions.AbstractTestAction.execute(AbstractTestAction.java:42)
            at com.consol.citrus.dsl.design.DefaultTestDesigner.applyBehavior(DefaultTestDesigner.java:193)
            at com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner.applyBehavior(TestNGCitrusTestDesigner.java:168)
            at com.grge.citrus.cmptest.stratus.CitrusLearning.mySimpleTest(CitrusLearning.java:194)
            at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
            at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
            at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
            at java.lang.reflect.Method.invoke(Method.java:498)
            at org.springframework.util.ReflectionUtils.invokeMethod(ReflectionUtils.java:216)
            at com.consol.citrus.testng.AbstractTestNGCitrusTest.invokeTestMethod(AbstractTestNGCitrusTest.java:121)
            at com.consol.citrus.dsl.testng.TestNGCitrusTest.invokeTestMethod(TestNGCitrusTest.java:121)
            at com.consol.citrus.dsl.testng.TestNGCitrusTestDesigner.invokeTestMethod(TestNGCitrusTestDesigner.java:73)
            at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:110)
            at com.consol.citrus.dsl.testng.TestNGCitrusTest.run(TestNGCitrusTest.java:56)
            at org.testng.internal.MethodInvocationHelper.invokeHookable(MethodInvocationHelper.java:242)
            at org.testng.internal.Invoker.invokeMethod(Invoker.java:579)
            at org.testng.internal.Invoker.invokeTestMethod(Invoker.java:719)
            at org.testng.internal.Invoker.invokeTestMethods(Invoker.java:989)
            at org.testng.internal.TestMethodWorker.invokeTestMethods(TestMethodWorker.java:125)
            at org.testng.internal.TestMethodWorker.run(TestMethodWorker.java:109)
            at org.testng.TestRunner.privateRun(TestRunner.java:648)
            at org.testng.TestRunner.run(TestRunner.java:505)
            at org.testng.SuiteRunner.runTest(SuiteRunner.java:455)
            at org.testng.SuiteRunner.runSequentially(SuiteRunner.java:450)
            at org.testng.SuiteRunner.privateRun(SuiteRunner.java:415)
            at org.testng.SuiteRunner.run(SuiteRunner.java:364)
            at org.testng.SuiteRunnerWorker.runSuite(SuiteRunnerWorker.java:52)
            at org.testng.SuiteRunnerWorker.run(SuiteRunnerWorker.java:84)
            at org.testng.TestNG.runSuitesSequentially(TestNG.java:1208)
            at org.testng.TestNG.runSuitesLocally(TestNG.java:1137)
            at org.testng.TestNG.runSuites(TestNG.java:1049)
            at org.testng.TestNG.run(TestNG.java:1017)
            at org.apache.maven.surefire.testng.TestNGExecutor.run(TestNGExecutor.java:135)
            at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.executeSingleClass(TestNGDirectoryTestSuite.java:112)
            at org.apache.maven.surefire.testng.TestNGDirectoryTestSuite.execute(TestNGDirectoryTestSuite.java:99)
            at org.apache.maven.surefire.testng.TestNGProvider.invoke(TestNGProvider.java:146)
            at org.apache.maven.surefire.booter.ForkedBooter.invokeProviderInSameClassLoader(ForkedBooter.java:373)
            at org.apache.maven.surefire.booter.ForkedBooter.runSuitesInProcess(ForkedBooter.java:334)
            at org.apache.maven.surefire.booter.ForkedBooter.execute(ForkedBooter.java:119)
            at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:407)
        09:27:51,555 INFO  port.LoggingReporter| ------------------------------------------------------------------------
        09:27:51,555 INFO  port.LoggingReporter| 
        09:27:51,595 INFO  port.LoggingReporter| 
        09:27:51,595 INFO  port.LoggingReporter| ------------------------------------------------------------------------
        09:27:51,595 DEBUG port.LoggingReporter| AFTER TEST SUITE

Thx a lot for any idea to fix this

Upvotes: 1

Views: 461

Answers (2)

Turing85
Turing85

Reputation: 20185

The problem you face is that

s=s.replaceAll("!!Name!!",myvar);

is not part of the Java DSL test. It is evaluated before the test runs. The behaviour is described in the Citrus documentat. The calls to echo(...), however, are part of the DSL and thus get executed when the test is actually run.

What you can do instead is let citrus take care of the replacement for you. You want to replace "!!Name!!" with the values of vm and i concatenated. To achieve this, replace "!!Name!!" with "${vm}${i}" in your template and let citrus do the heavy lifting for your:

        String func_replace(String myvar)
        {
          String s = "This is a string in which to replace ${vm}${id} by the value of my citrus variable but it crashes";
          echo("[func_replace] OK ->in func_replace");
          echo("[func_replace] myvar="+ myvar + " - OK ->variable from Test is correctly transmitted to func_asis");
          return s;
        }

As the returned String is used within apply() in class myBehavior through echo(...), citrus does the substition for you.

Upvotes: 1

fckbo
fckbo

Reputation: 167

having putting some more time into it, I start to understand how Citrus treats variables, in the case above the value of 'myvar' is actually set to "${vm}${i}" and will be replaced at execution time but when being invoked from a test action.... So I looked at custom test action to find that even there sometime variable instantiation is a bit tricky... but nevertheless I could achieve the first part of what I wanted to do which is to replace some predefined values in a string by variables content. See below the snippet that does this.

...But now because I invoke the replace function from an action, I cannot return a string to the invoker which was what I was planning to do in my behavior ... so will investigate if & how that's possible or will look at some other design for my test (like temporary file to store the string with replaced values being read by the behavior after func_replace would have updated them..) Anyway here is a solution to the problem I had above:


@Test
public class CitrusLearningL4 extends TestNGCitrusTestDesigner {

    public class myBehavior extends AbstractTestBehavior {

        private @CitrusResource TestContext parentContext;        

        myBehavior withContext(@Optional @CitrusResource TestContext context) {
            this.parentContext=context;
            return this;
        }

        @Override
        public void apply() {
            echo("[behavior] - OK ->behavior is invoked");
            func_replace();
            echo("[behavior] - OK ->behavior is finished");

        }

        void func_replace()
        {
          final String s = "This is a string in which '!!Name!!' is present because it was replaced by the value of my test variable";
          echo("[func_replace] OK ->in func_replace");
          action(new AbstractTestAction() {
                public void doExecute(TestContext context) {
                  String s1 = s;
                  System.out.println("[anAction] - OK ->anAction is invoked"); 
                  String sVar=String.format("%s", (String) parentContext.getVariable("vm") + (String) parentContext.getVariable("i"));
                  System.out.println("[anAction] - OK ->" + s1.replaceAll("!!Name!!",sVar));      
                }
              });         
        }

    }

    @Test @Parameters("context")
    @CitrusTest 
    public void mySimpleBehaviorTest(@Optional @CitrusResource TestContext context) throws IOException {
      description("Simple Test invoking a behavior which it self will invoke a java function");
      variable("vm", "/dc/vm/folder/vm_basename");

      repeat().until("i = 3")
            .actions(
              sleep(1000L),
              applyBehavior(new myBehavior().withContext(context))
            ); 
    }

}

Upvotes: 1

Related Questions