TestNG, is there a class level listener like IClassListener like ITestListener - selenium

I want to perform same action for every class (just like #BeforeClass). I guess listeners can do things where you don't have to write code individually, but I did not find in each method/class but can be executed via a listener. Is there a way to execute my method before every class or just once before method of that class?

Check the beforeConfiguration() method in TestListenerAdapter.
#Override
public void beforeConfiguration(ITestResult tr) {
if(tr.getMethod().getMethodName().equals("methodNameForBeforeClass")) {
//...
}
}

Try configuration related methods in TestListenerAdapter:
class TestNGListener extends TestListenerAdapter {
#Override
public void beforeConfiguration(ITestResult tr) {
super.beforeConfiguration(tr);
logger.info("=========== Configuration method '{}' started ===========", tr.getMethod().getMethodName());
}
#Override
public void onConfigurationSuccess(ITestResult tr) {
super.onConfigurationSuccess(tr);
logger.info("=========== Configuration method '{}' finished ===========", tr.getMethod().getMethodName());
}
#Override
public void onConfigurationFailure(ITestResult tr) {
super.onConfigurationFailure(tr);
logger.error("!!!!!!!!!!! Configuration method '{}' failed !!!!!!!!!!!", tr.getMethod().getMethodName());
}
}

Extend TestListenerAdapter and override onTestStart(ITestResult result) method. This will help you to run something everytime a test starts

Related

How to avoid Blockhound catching blocking call when setting up data?

In my integration test I'm using BlockHound to capture any blocking call.
For setting up the data I am doing a blocking call because I want the data to be persisted in the DB when running each test.
When running the integration test Blockhound is throwing an error at the set up method: reactor.blockhound.BlockingOperationError: Blocking call! java.io.FileInputStream#readBytes
How to avoid this?
#BeforeAll
public static void blockHoundSetup() {
BlockHound.install();
}
#BeforeEach
public void setUp() {
stagingAreaAdapter.deleteAll()
.thenMany(Flux.fromIterable(data))
.flatMap(stagingAreaAdapter::save)
.blockLast();
}
Check BlockHound customizations for allowing and disallowing blocking calls inside methods:
https://github.com/reactor/BlockHound/blob/master/docs/customization.md#dis-allowing-blocking-calls-inside-methods
1. using builder in a #BeforeAll method (as per #KrisKris1):
#BeforeAll
public static void blockHoundSetup() {
BlockHound.builder().allowBlockingCallsInside(
TestClass.class.getName(), "setUp").install();
}
or
2. via implementing the BlockHoundIntegration interface (still applies globally):
public class BlockHoundCustomConfiguration implements BlockHoundIntegration {
#Override
public void applyTo(BlockHound.Builder builder) {
builder.allowBlockingCallsInside("java.base/java.io.RandomAccessFile", "readBytes");
}
}
and create the following file:
<project dir>/src/test/resources/META-INF/services/reactor.blockhound.integration.BlockHoundIntegration
with your custom class:
com.example.config.BlockHoundCustomConfiguration
You need to allow blocking method calls inside java.util.zip.InflaterInputStream#read down the callstack.
Add in your BlockHound customization config.
public class ReactorBlockHoundIntegration implements BlockHoundIntegration {
#Override
public void applyTo(BlockHound.Builder builder) {
builder.allowBlockingCallsInside(InflaterInputStream.class.getName(), "read");
}
}
https://docs.oracle.com/javase/8/docs/api/index.html?java/util/zip/package-summary.html

Retry Logic - retry whole class if one tests fails - selenium

Following are the classes used to implement retry logic
TestRetry Class:
public class TestRetry implements IRetryAnalyzer {
int counter=0;
int retryLimit=2;
#Override
public boolean retry(ITestResult result) {
if (counter < retryLimit) {
TestReporter.logStep("Retrying Test " +result.getName()+" for number of times: "+(counter+1));
counter++;
return true;
}
return false;
}
RetryListener Class:
public class RetryListener implements IAnnotationTransformer {
#Override
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
// TODO Auto-generated method stub
IRetryAnalyzer retry = annotation.getRetryAnalyzer();
if (retry == null) {
annotation.setRetryAnalyzer(TestRetry.class);
}
}}
SampleTest:
#Listeners(RetryListener.class)
public class SampleTest {
#BeforeSuite(alwaysRun = true)
public void beforeSuite(ITestContext context) {
for (ITestNGMethod method : context.getAllTestMethods()) {
method.setRetryAnalyzer(new TestRetry());
}
}
#Test(priority=0)
public void firsttest() {
System.out.println();
TestReporter.assertEquals("Test", "Test", "pass");
}
#Test(priority=1, dependsOnMethods="firsttest")
public void secondtest() {
TestReporter.assertEquals("Test", "Test1", "fail");
}
#Test(priority=2,dependsOnMethods="secondtest")
public void thirdtest() {
TestReporter.assertEquals("Test", "Test", "pass");
}
}
When I execute the above test, following is the output
firsttest gets executed and passes
secondtest depends on firsttest and gets executed, its failed - Retried 3 times and failed again
thirdtest skipped because it depends on secondtest.
Output achieved as expected.
Question:
Since the tests are dependent. If one of the tests fails, I want to execute the whole class from first. is there a way to do it?
Examples:
If secondtest fails, I want to execute the whole class SampleTest again.
Thanks!
There's currently no way of achieving what you are asking for.
TestNG will only retry a failed test, but will not go up the execution ladder to find out all the upstream dependencies and try running them as well (Your ask is a very specific variant of this generic use case).
If you come to think of it, a dependent test is being executed only because its upstream dependencies (methods on which it depends on) have been executed successfully. So if there's a failure in the current test, why would one need to re-execute the already satisfied upstream dependencies? Its counter intuitive.
For what you have as a use-case, you should be merely building the entire logic within a #Test method, wherein you take care of handling the retries and also the invocation of the entire chain once again, if there were failures.
The below sample should clarify that
public class SampleTest {
#Test (retryAnalyzer = TestRetry.class)
public void orchestrateTest() {
firsttest();
secondtest();
thirdtest();
}
public void firsttest() {
System.out.println();
TestReporter.assertEquals("Test", "Test", "pass");
}
public void secondtest() {
TestReporter.assertEquals("Test", "Test1", "fail");
}
public void thirdtest() {
TestReporter.assertEquals("Test", "Test", "pass");
}
}
TestNG does not support the use case that you are looking for in your question.
On a side note, you cannot wire in a IAnnotationTransformer listener via an #Listeners annotation (this is explicitly called out in the javadocs of this interface). It can only be wired in via the <listeners> tag in your suite xml (or) by referring to it in the META-INF\services\org.testng.ITestNGListener file (its called the Service Provider Interface approach in Java)

JavaPsiScanner doesn't see calls

I'm working on a custom Lint check and can't get all the method calls I need.
What I need: access to every add() call in lines like this:
Builder.from(arg)
.add(arg1, arg2)
.add(arg1, arg2)
.add(arg1, arg2);
What I get: visitMethod is not called at all. In such lines it's only called for 'from()'.
Detector code sample:
public class ExampleDetector extends Detector implements Detector.JavaPsiScanner {
#Override
public List<String> getApplicableMethodNames() {
return Collections.singletonList("add");
}
#Override
public void visitMethod(JavaContext context, #Nullable JavaElementVisitor visitor,
#NonNull PsiMethodCallExpression call, #NonNull PsiMethod method) {
...
}
....
}
How can I solve it? Why is it not visited at all?

how to pass context arguments to advice in spring aop

I am learning spring aop now,and I have no idea to pass context arguments to the advice.
Note I mean the context arguments,not the normal arguments.
It is simple to pass the normal arguments,for example:
a join point:
public void read(String something){
}
#Aspect
public class SessionAspect {
#Pointcut("execution(* *.*(String)) &&args(something)")
public void sess() {
}
#Before("sess()")
public void checkSessionExist(String something) {
//Here
}
}
Then the something argument will be passed to the the advice checkSessionExist.
But how about I want to get the context arguments like HttpSession or something else?
a join point:
public void listUser(){
dao.list(User.class,.....);
}
#Aspect
public class SessionAspect {
#Pointcut("execution(* *.*(String))")
public void sess() {
}
#Before("sess()")
public void checkSessionExist(String something) {
//Here
}
}
In this example,the listUser join point is only allowed for logined user.
So I want to check if there is a identify in the current HttpSession,so I need to get an instance of HttpSession at the advice checkSessionExist.
But how to get it?
The simplest way is to add the HttpSession argumets to all the joit points like this:
public void listUser(HttpSession session){
dao.list(User.class,.....);
}
However this have gone against the AOP it self. In my opinion,the join point even does not need to know the exist of the Aspect,isn't it?
How to fix it ?
Instead of passing HttpSession via #Pointcuts, you could fetch HttpSession reference in the #Aspect itself
RequestContextHolder.currentRequestAttributes()
.getAttribute("user", RequestAttributes.SCOPE_SESSION)
#Aspect
public class SessionAspect {
// fetch the current HttpSession attributes and use as required
private ServletRequestAttributes attr = (ServletRequestAttributes) RequestContextHolder.currentRequestAttributes();
#Pointcut("execution(* *.*(String))")
public void sess() {
}
#Before("sess()")
public void checkSessionExist(String something) {
//Here
}
}

Google Guice, Interceptors and PrivateModules

New poster here, hope I don't brake any rules :)
I am using PrivateModule in google-guice in order to have multiple DataSource's for the same environment. But I am having a hard time getting MethodInterceptor's to work inside the private modules.
Below is a simple test case that explains the "problem".
A simple service class would be:
interface Service {
String go();
}
class ServiceImpl implements Service {
#Override #Transactional
public String go() {
return "Test Case...";
}
}
The MyModule class would be:
class MyModule extends AbstractModule {
#Override
protected void configure() {
install(new PrivateModule() {
#Override
protected void configure() {
bind(Service.class).to(ServiceImpl.class);
bindInterceptor(
Matchers.any(),
Matchers.annotatedWith(Transactional.class),
new MethodInterceptor() {
#Override
public Object invoke(MethodInvocation i)
throws Throwable {
System.out.println("Intercepting: "
+ i.getMethod().getName());
return i.proceed();
}
});
expose(Service.class);
}
});
}
}
And the final test case:
public class TestCase {
#Inject Service service;
public TestCase() {
Guice.createInjector(new MyModule()).injectMembers(this);
}
public String go() {
return service.go();
}
public static void main(String[] args) {
TestCase t = new TestCase();
System.out.println(t.go());
}
}
You would expect the output to be:
Intercepting: go
Test Case...
But it doesn't happen, the interceptor is not used, ant only Test Case... is output.
If I bind/expose the ServiceImpl instead of the interface then it works.
Thanks in advance,
Regards,
LL
Well... I figured it out shortly after I posted the question :)
The problem is that you also need to expose() the ServiceImpl class.
So the bind/expose would be.
bind(ServiceImpl.class); // ServiceImpl annotated with #Singleton
bind(Service.class).to(ServiceImpl.class);
expose(ServiceImpl.class);
expose(Service.class);
Regards,
LL
You need to explicitly bind ServiceImpl in the private module. The problem with your existing code is that it inherits the binding for ServiceImpl from the parent module. From the PrivateModule docs,
Private modules are implemented using parent injectors. When it can satisfy their dependencies, just-in-time bindings will be created in the root environment. Such bindings are shared among all environments in the tree.
Adding this line should fix the problem:
bind(ServiceImpl.class);