Accessing values in annotation of a test in a different class - TestNg - java

I have a custom Annotation I created as below
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface TestConfig {
String[] value();
}
I have test that extends a BaseClass.
import org.testng.annotations.Test;
public class MyTest extends BaseClass {
#Test
#TestConfig({ "enableCookies" })
public void startTest() {
startInstance();
}
}
Now I need to access the values inside #TestConfig annotation inside my BaseClass which is below
import org.testng.annotations.BeforeSuite;
public class BaseClass {
public void startInstance() {
System.out.println("starting instance");
//I need to access the value supplied in "MyTest" inside #TestConfig annotation here. How do I do that.
}
#BeforeSuite
public void runChecks() {
System.out.println("Checks done....");
}
}
I know I can do TestConfig config = method.getAnnotation(TestConfig.class) but how do I access the TestNG TestMethodclass? Please help.

You can do something like (but remove the direct call in the test method):
#BeforeMethod
public void startInstance(Method m) {
System.out.println("starting instance");
//I need to access the value supplied in "MyTest" inside #TestConfig annotation here. How do I do that.
TestConfig tc = m.getAnnotation(TestConfig.class);
System.out.println(tc.value());
}

Related

Create custom method level annotation only available to specific return types [AOP]

I want to create an annotation which is only available to a specific type of return values.
For example this is my annotation.
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.METHOD})
public #interface MyAnnotation {
}
I also have an interface:
public interface MyInterface {
String generateKey();
}
An example class that implements my interface:
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
So after these, I want to configure my annotation in a way that it won't even compile if the return type is not implementing MyInterface.
In this case, I expect this to compile fine:
#MyAnnotation
public ExampleClass anExampleMethod() {
return new ExampleClass();
}
And this to not compile:
#MyAnnotation
public String anotherMethod() {
return "Whatever";
}
I wonder if this is possible in any way. Sure I can check if the parameters implements this interface in my Aspect class but it would be better to have this kind of protection in my library in order to prevent misuse of any annotation.
Helper classer:
These are directly from your example, just with package names and imports.
package de.scrum_master.app;
import static java.lang.annotation.ElementType.METHOD;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
#Retention(RUNTIME)
#Target(METHOD)
public #interface MyAnnotation {}
package de.scrum_master.app;
public interface MyInterface {
String generateKey();
}
package de.scrum_master.app;
public class ExampleClass implements MyInterface {
#Override
public String generateKey() {
return "Whatever";
}
}
Class which should not compile:
This class has some annotated and some non-annotated methods. One annotated method does not return MyInterface or any of its implementing classes. The goal is to fail compilation.
package de.scrum_master.app;
public class Application {
#MyAnnotation
public MyInterface annotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
#MyAnnotation
public ExampleClass annotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
#MyAnnotation
public String annotatedMethodReturningSomethingElse() {
// This one should not compile!
return "Whatever";
}
public MyInterface nonAnnotatedMethodReturningInterface(int number) {
return new ExampleClass();
}
public ExampleClass nonAnnotatedMethodReturningImplementingClass() {
return new ExampleClass();
}
public String nonAnnotatedMethodReturningSomethingElse() {
return "Whatever";
}
}
Convention-checking aspect (native AspectJ syntax):
package de.scrum_master.aspect;
import de.scrum_master.app.MyAnnotation;
import de.scrum_master.app.MyInterface;
public aspect AnnotationCheckerAspect {
declare error :
#annotation(MyAnnotation) && execution(* *(..)) && !execution(MyInterface+ *(..)) :
"Method annotated with #MyAnnotation must return MyInterface type";
}
This aspect checks for
all method executions
where the method has #MyAnnotation
but where the return type is different from MyInterface or any subtype or implementing class.
This is what the result looks like in Eclipse:
Of course the compilation error is just the same if you compile from command line or via AspectJ Maven plugin or similar.
If you do not like native syntax (I prefer it but for some incomprehensible reason other people seem to prefer #AspectJ style):
Convention-checking aspect (annotation-based #AspectJ syntax):
package de.scrum_master.aspect;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.DeclareError;
#Aspect
public class AnnotationCheckerAspect {
#DeclareError(
"#annotation(de.scrum_master.app.MyAnnotation) && " +
"execution(* *(..)) && " +
"!execution(de.scrum_master.app.MyInterface+ *(..))"
)
static final String wrongSignatureError =
"Method annotated with #MyAnnotation must return MyInterface type";
}
See also my related answers here:
https://stackoverflow.com/a/27121947/1082681
https://stackoverflow.com/a/54067850/1082681
https://stackoverflow.com/a/41700647/1082681
https://stackoverflow.com/a/27312472/1082681
https://stackoverflow.com/a/50126576/1082681

How do I disable a test from running in a subclass in TestNG?

(Update: After I reported this, the TestNG team confirmed the bug.)
Normally, ignoring a class can be done with #Ignore or enabled=false
This does not work on a subclass where test methods are defined in its superclass (and where the subclass defines its specific functionality in hook methods). See ChildClassTest below.
Note that #Ignore is specific to JUnit whereas TestNG uses enabled.
Base class
import org.testng.annotations.Test;
public class ParentClassTest {
#Test
public void test1() {
hook();
}
protected void hook() {};
}
Child class
import org.testng.Reporter;
import org.testng.annotations.Ignore;
#Ignore
public class ChildClassTest extends ParentClassTest {
#Override
protected void hook() {
Reporter.log("ChildClassTest#hook()");
}
}
Been doing some brainstorming out of curiosity, and came up with the workarounds below tested with v6.14.2. I personally prefer the first one, being cleaner, more elegant, flexible and easier to maintain and extend.
context
import org.testng.annotations.Test;
import static org.testng.Assert.assertTrue;
public class MyTest {
#Test
public void shouldRun() {
assertTrue(true);
}
#Test
public void shouldNotRun() {
assertTrue(true);
}
#Test
public void shouldNotRunEither() {
assertTrue(true);
}
}
1) Using listeners - create a TestListenerAdapter & annotation to skip methods with certain names: flexible, clear, easy to reuse and identify for removal. The only downside is that you have to pay attention to method names for typos.
Annotation
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Retention(RetentionPolicy.RUNTIME)
#Target({ElementType.TYPE})
public #interface SkipMethods {
String[] value() default {};
}
TestListenerAdapter
import org.testng.ITestResult;
import org.testng.SkipException;
import org.testng.TestListenerAdapter;
public class TestSkippingListener extends TestListenerAdapter {
#Override
public void onTestStart(ITestResult result) {
// get the skip annotation
SkipMethods skipAnnotation = result.getMethod().getInstance().getClass().getAnnotation(SkipMethods.class);
// if the annotation exists
if (skipAnnotation != null) {
for (String skippableMethod : skipAnnotation.value()) {
// and defines the current method as skippable
if (skippableMethod.equals(result.getMethod().getMethodName())) {
// skip it
throw new SkipException("Method [" + skippableMethod + "] marked for skipping");
}
}
}
}
}
Test Subclass
import org.testng.annotations.Listeners;
// use listener
#Listeners(TestSkippingListener.class)
// define what methods to skip
#SkipMethods({"shouldNotRun", "shouldNotRunEither"})
public class MyTestSkippingInheritedMethods extends MyTest {
}
Result
2) Override methods from superclass and throw SkipException: pretty clear, no possibility of typo, but not reusable, not easily maintainable & introduces useless code:
import org.testng.SkipException;
public class MyTestSkippingInheritedMethods extends MyTest {
#Override
public void shouldNotRun() {
throw new SkipException("Skipped");
}
#Override
public void shouldNotRunEither() {
throw new SkipException("Skipped");
}
}
Result

Change value of guice instance on runtime

I´m using google guice to inject this class example
class A {
String a;
}
Then is injected in my class B
class B {
#Inject A aInstance;
public void checkValue(){
System.out.println(aInstance.a);
}
}
Maybe using aspectJ, but what I would like is, that one test of mine, would get this A instance and would set the "a" string as "foo", before execute the test that cover the B class, so when the B class invoke checkValue this one would print "foo"
You mention the word test in your question - if you are writing a jUnit test for B you could perform the injection in an #Before clause, as demonstrated here.
private Injector injector;
#Before
public void init() throws Exception {
injector = Guice.createInjector(new AbstractModule() {
#Override
protected void configure() {
bind(A.class).to(MockedInstanceOfAWithValueFoo.class);
}
});
}
You could also call
bind(A.class).toInstance(new MockedInstanceOfAWithValueFoo());
If we assume that A has a constructor by which we can define A.a, the mocked instance could look like this:
public class MockedInstanceOfAWithValueFoo extends A{
public MockedInstanceOfAWithValueFoo() {
super("foo");
}
}
Again, you could make your mocked class accept the value of A.a through a constructor to make the creation of B (and the associated value of A.a) more dynamic.
With Mockito:
import static org.junit.Assert.assertNotNull;
import static org.mockito.Mockito.when;
import org.junit.Before;
import org.junit.Test;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
public class MyTest {
#Mock
A mockA;
#InjectMocks
B mockB;
#Before
public void init() {
MockitoAnnotations.initMocks(this);
mockA.a = "Foo";
//when(mockA.getA()).thenReturn("Foo"); //if you use getter
}
#Test
public void myTest() {
assertNotNull(mockA);
assertNotNull(mockA.a);
assertNotNull(mockB);
assertNotNull(mockB.ainstance);
mockB.checkValue();
}
}

How to get method result with annotation?

I want to get the result of a method and then enqueue them into ActiveMQ. Hence, I decided to create an annotation(say #Enqueue("My_Queue")) that gets the result and send it to My_Queue.
#ResponseBody
#Enqueue("My_Queue")
#RequestMapping("/list")
public MyClass list() {
return myService.getAll();
}
And here is the annotation itself:
#Target(value = ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Enqueue {
/**
* The Name Of The Queue
*/
String value() default "General_Message_Queue";
}
So What should I do to create such an annotation(A-Z please)?
Aspects must be what your looking for. Since you're using Spring, have a look as Spring AOP: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html.
With the advice #AfterReturning and the pointcut #annotation(package.to.Enqueue), you'll be able to access the returned value each time a method annotated with #Enqueue is called: http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html#aop-advice-after-returning.
You'll then be able to send it to the queue.
You need to write below code snap.
Class aClass = MyClass.class;
Annotation[] annotations = aClass.getAnnotations();
for(Annotation annotation : annotations){
if(annotation instanceof Enqueue ){
Enqueue myAnnotation = (Enqueue ) annotation;
if(myAnnotation.name().equals("Enqueue")){
//do your work
System.out.println("value: " + myAnnotation.value());
}
}
}
Update :
Annotations are not "triggered"... you have to write code that looks for their presence and takes action.
The "code" can either be executed at runtime, but is more commonly executed at compile time using the Annotation Processing Tool to alter the source to inject extra, typically cross-cutting, code appropriate for the annotation.
Reference link : https://stackoverflow.com/a/13040933/1326692
Update : By seeing your comments it seems that you want something by which dynamically you can do your stuff before your annotation method call. For this you need to create proxy like given below.
1: MyInterface.java
public interface MyInterface {
void test();
}
2: Enqueue.java
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
#Target(ElementType.METHOD)
#Retention(RetentionPolicy.RUNTIME)
public #interface Enqueue {
public String value() default "General_Message_Queue";
}
3. MyClass.java
import java.lang.reflect.Proxy;
public class MyClass implements MyInterface {
#Enqueue
public void test() {
System.out.println("Inside test");
}
public static void main(String[] args) throws IllegalArgumentException, InstantiationException, IllegalAccessException {
MyInterface test = (MyInterface) getProxyInstance(MyClass.class, MyInterface.class);
test.test();
}
#SuppressWarnings("rawtypes")
public static Object getProxyInstance(Class clazz, Class interfaze) throws IllegalArgumentException,
InstantiationException, IllegalAccessException {
Object proxy =
Proxy.newProxyInstance(MethodInvocationHandler.class.getClassLoader(),
new Class[] {interfaze}, new MethodInvocationHandler(clazz.newInstance()));
return proxy;
}
}
4: MethodInvocationHandler.java
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class MethodInvocationHandler implements InvocationHandler {
private Object proxied;
public MethodInvocationHandler(Object proxied) {
this.proxied = proxied;
}
#Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Method m = proxied.getClass().getMethod(method.getName(), method.getParameterTypes());
if (m.isAnnotationPresent(Enqueue.class)) {
// do your work here
System.out.println("Before " + m.getName() + " call..!");
/** also you can get annotation and access it's properties..! */
Enqueue annotation = m.getAnnotation(Enqueue.class);
System.out.println("name: " + annotation.value());
}
/** also you can get all the annotations if you want */
Annotation[] annotations = method.getDeclaredAnnotations();
for (Annotation annotation : annotations) {
// do your annotation specific work here like this,
if (annotation instanceof Enqueue) {
// do your work here.
}
}
return method.invoke(proxied, args);
}
}
I hope it helps :)
If you are using spring-aop or any third party aop library then you can apply below code.
import java.util.ArrayList;
import java.util.Collection;
import org.apache.log4j.Logger;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;
#Aspect
#Component
public class EnqueueServiceMonitor {
private static final Logger LOGGER = Logger
.getLogger(EnqueueServiceMonitor.class);
public EnqueueServiceMonitor() {
}
#AfterReturning(value = "#annotation(com.enqeue.annotation.Enqueue) && args(myClass,..)")
public void doProcess(MyClass myClass,
Exception ex) {
//do the code here. This method will call every time whenever your MyClass.list() method will be called.
//Or other method which have this annotation and return myClass object.
}
}
#ResponseBody
#Enqueue("My_Queue")
#RequestMapping("/list")
public MyClass list() {
return myService.getAll();
}
If your method have different return type then you have to write more aop advice for specific return type.

Access annotation at runtime

How can I access in main whether check in the Sample class is true or false?
What should I write in Main class?
package annotation;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
#Retention(RetentionPolicy.RUNTIME)
public #interface annotation {
public String name() default "Jimmy";
public boolean check() default false;
}
package annotation;
#annotation(name = "Jack", check = false)
public class Sample {
public String str = "Hi";
public void printHi(String str) {
System.out.println(str);
}
}
package annotation;
public class Main {
public static void main(String[] args) {
}
}
Use Sample.class.getAnnotation(annotation.class) to get your annotation instance, and call check() to get the check value:
System.out.println(Sample.class.getAnnotation(annotation.class).check());
Note that classes should start with an upper-case letter, and that naming an annotation "annotation" is quite confusing.

Categories