1

Basically, I wanted to use a constant boolean attribute of Context class which I have changed via reflection so that I can dynamically set the @annotated enabled for a testNG method in a TestNG class. The TestNG class has a static final attribute which is the same as the Context.DISBLE_TEST_CASES_IF_OLD_STACK. I have pasted the code below for the TestNG class and its method. The end goal for me is to toggle the enabled value or basically disable the test based on the the context if its old environment or new environment

 package com.abc.api.core.context;

    import java.lang.reflect.Field;
    import java.lang.reflect.Modifier;


    public class Context {
        public static final boolean DISBLE_TEST_CASES_IF_OLD_STACK = getConstantReflection();


        public static boolean getConstantReflection()
        {
            System.out.println(DISBLE_TEST_CASES_IF_OLD_STACK);
            try {
                setEnableFlagBasedOnStackForTestCases();
            } catch (NoSuchFieldException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (SecurityException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalArgumentException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                // TODO Auto-generated catch block
                e.printStackTrace();
            }
            System.out.println(Context.DISBLE_TEST_CASES_IF_OLD_STACK);
            try {
                final Field fld = Context.class.getDeclaredField("DISBLE_TEST_CASES_IF_OLD_STACK");
                return (Boolean) fld.get( null );
            } catch (NoSuchFieldException e) {
                return (Boolean) null;
            } catch (IllegalAccessException e) {
                return (Boolean) null;
            }
        }

        private static void setEnableFlagBasedOnStackForTestCases() throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException{


            Field f = Context.class.getDeclaredField("DISBLE_TEST_CASES_IF_OLD_STACK");
            f.setAccessible(true);

            //'modifiers' - it is a field of a class called 'Field'. Make it accessible and remove
            //'final' modifier for our 'CONSTANT' field
            Field modifiersField = Field.class.getDeclaredField( "modifiers" );
            modifiersField.setAccessible( true );
            modifiersField.setInt( f, f.getModifiers() & ~Modifier.FINAL );

            if (TestcaseContext.getContext().equalsIgnoreCase(Context.OLD_STACK)) {
                f.setBoolean(null, false);
            }else {
                f.setBoolean(null, true);
            }
        }

    }

TESTNG CLASS AND METHOD example:

package com.abc.api.test.tests.TestA;

import com.abc.api.core.context.Context;

public class TestA extends TestCommon {

    private static final boolean ENABLE_DISABLE = Context.DISBLE_TEST_CASES_IF_OLD_STACK;

    /**
     * 
     */
    @BeforeTest
    void setPropertiesFile() {
      ......

    }

    /**
     * PATCH Positive Test Cases
     * 
     */

    @Test(priority = 11, enabled=ENABLE_DISABLE)
    public void testPositive1() {
        ......
    }
}
sophist_pt
  • 329
  • 1
  • 8
  • 19
  • 2
    Your `DISBLE_TEST_CASES_IF_OLD_STACK` is not a constant variable. You won't be able to use that in an annotation. – Sotirios Delimanolis Aug 28 '17 at 20:29
  • But isn't reflection essentially modifying the static final value which is actually a constant attribute of the class. Hence I went through this path of using reflection. – sophist_pt Aug 28 '17 at 20:34
  • 2
    https://stackoverflow.com/questions/10636201/java-annotations-values-provided-in-dynamic-manner – Sotirios Delimanolis Aug 28 '17 at 20:35
  • The compiler is permitted to copy constant variable values directly and never actually read them at runtime, so this wouldn't work even if it did compile. See e.g. https://ideone.com/WT9j9z – Radiodef Aug 28 '17 at 21:00

1 Answers1

2

To the end goal of selectively disabling testcases, you can use TestNgs IAnnotationTransformer to control the enabled flag. It will be run before each @Test annotated method and can control it's execution.

eg.

public class DemoTransformer implements IAnnotationTransformer {
  public void transform(ITest annotation, Class testClass,
      Constructor testConstructor, Method testMethod)
  {
    if (condition) {
        annotation.setEnabled(false/true);
  }
}
niharika_neo
  • 8,441
  • 1
  • 19
  • 31
  • Thats exactly what I ended up doing. However, for some reason when I annotated the TestNG class with the listener class the listener was not invoked. I had to use the listener through xml in the test suite, which is kind of a bummer because I wanted to apply this listener to just this particular class. Also, I found out that I could just use groups and exclude and include them as per need. – sophist_pt Aug 29 '17 at 05:05