@BeforeMethod/@AfterMethod(onlyForGroups) methods did not execute, if a test method belonging to this group is executed

Viewed 1068

I am running a test suite with the test methods belonging to a certain groups.

Below is the Selenium code:

public class BaseClass
{

    @BeforeMethod(onlyForGroups = {"P1"})
    public void bmeth1()
    {
        System.out.println("Before Method1 called");
    }

    @BeforeMethod(onlyForGroups = {"P2"})
    public void bmeth2()
    {
        System.out.println("Before Method2 called");
    }

    @BeforeMethod(onlyForGroups = {"P3"})
    public void bmeth3()
    {
        System.out.println("Before Method3 called");
    }

    @AfterMethod(onlyForGroups = {"P1"})
    public void ameth1()
    {
        System.out.println("After Method1 called");
    }

    @AfterMethod(onlyForGroups = {"P2"})
    public void ameth2()
    {
        System.out.println("After Method2 called");
    }

    @AfterMethod(onlyForGroups = {"P3"})
    public void ameth3()
    {
        System.out.println("After Method3 called");
    }

}

public class TC_003 extends BaseClass
{

    @Test(groups = {"P1"})
    public void tCase6()
    {
        System.out.println("Inside testcase 6");
    }

    @Test(groups = {"P2"})
    public void tCase7()
    {
        System.out.println("Inside testcase 7");
    }

    @Test(groups = {"P3"})
    public void tCase8()
    {
        System.out.println("Inside testcase 8");
    }

}

Below is the testng.xml file:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "https://testng.org/testng-1.0.dtd">
<suite name="Suite" verbose="10">
<test name="Test1">
    <groups>
        <run>
            <include name=".*"/>
        </run>
    </groups>
    <classes>
        <class name="testing.TC_003"/>
    </classes>
</test>
</suite>

Actual Output:

Inside testcase 6
Inside testcase 7
Inside testcase 8

Expected Output:

Before Method1 called
Inside testcase 6
After Method1 called
Before Method2 called
Inside testcase 7
After Method2 called
Before Method3 called
Inside testcase 8
After Method3 called

The test methods are executed, but the @BeforeMethod/@AfterMethod did not execute. This issue occurs only if we include certain groups in testng.xml file. But if we exclude certain groups or do not use groups tag in testng.xml file, then they are executed.

As suggested here, the current workaround is to use alwaysRun=true flag along with onlyForGroups flag. But if we apply this workaround, and if there is any SkipException in the preceding/parent config methods, then it is forced to execute the @BeforeMethod/@AfterMethod methods, even when the test method is going to be skipped. There is a similar issue logged here, when the preceding/parent config methods has failed.

3 Answers

Its an interesting observation if you change onlyforgroups to groups then everything works:

but when there are multiple groups included in your testng.xml then all before and after method in mentioned group get executed before every test method . so in order to avoid this you have to mix groups and onlygroups together

Explanation:

If you don't specify group in testng xml then all methods get invoked. but if you mention group then only methods in that particular group get executed.

this is because if you read the definition of groups:

https://testng.org/doc/documentation-main.html

groups The list of groups this class/method belongs to.

so if you don't mention the group or always run true then the method is not invoked so you won't get the before and after method invoked as they are not in any group

Work around:

you can mix the two as :

package driversetup;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;



public class TestBaseClass  {
    

    @BeforeMethod(onlyForGroups = {"P1"},groups = {"P1"})
    public void bmeth1()
    {
        System.out.println("Before Method1 called");
    }

    @BeforeMethod(onlyForGroups = {"P2"},groups = {"P2"})
    public void bmeth2()
    {
        System.out.println("Before Method2 called");
    }

    @BeforeMethod(onlyForGroups = {"P3"},groups = {"P3"})
    public void bmeth3()
    {
        System.out.println("Before Method3 called");
    }

    @AfterMethod(onlyForGroups = {"P1"},groups = {"P1"})
    public void ameth1()
    {
        System.out.println("After Method1 called");
    }

    @AfterMethod(onlyForGroups = {"P2"},groups = {"P2"})
    public void ameth2()
    {
        System.out.println("After Method2 called");
    }

    @AfterMethod(onlyForGroups = {"P3"},groups = {"P3"})
    public void ameth3()
    {
        System.out.println("After Method3 called");
    }
    

}

or enable always run true

package driversetup;

import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;



public class TestBaseClass {
    

    @BeforeMethod(onlyForGroups = {"P1"},alwaysRun = true)
    public void bmeth1()
    {
        System.out.println("Before Method1 called");
    }

    @BeforeMethod(onlyForGroups = {"P2"},alwaysRun = true)
    public void bmeth2()
    {
        System.out.println("Before Method2 called");
    }

    @BeforeMethod(onlyForGroups = {"P3"},alwaysRun = true)
    public void bmeth3()
    {
        System.out.println("Before Method3 called");
    }

    @AfterMethod(onlyForGroups = {"P1"},alwaysRun = true)
    public void ameth1()
    {
        System.out.println("After Method1 called");
    }

    @AfterMethod(onlyForGroups = {"P2"},alwaysRun = true)
    public void ameth2()
    {
        System.out.println("After Method2 called");
    }

    @AfterMethod(onlyForGroups = {"P3"},alwaysRun = true)
    public void ameth3()
    {
        System.out.println("After Method3 called");
    }
    

}

this ensures that the before and after method gets invoked, but get executed only for correct @test methods

I'm not sure about this regex for all groups, so just try to remove these lines:

<groups>
    <run>
        <include name=".*"/>
    </run>
</groups>

Below is the workaround for the issue mentioned in the original post:

If we want to execute certain groups only, then instead of using include for the groups which we want to execute, we can exclude those groups which we do not want to execute.
Similarly, if we want to execute all the groups, then instead of using <include name=".*"/>, use exclude and give some group name which is not there in your test suite for e.g.<exclude name="unknown"/> or <exclude name=""/>.
But please note that while using the above workarounds, it will also include and run all those tests which do not belong to any group. So, we have to apply one more workaround by assigning a default group to all those test and config methods which we believe do not belong to any specific group.

So, if we apply the above workarounds, then we do not have to apply the workaround mentioned in the original post i.e. we do not have to use alwaysRun=true flag along with onlyForGroups. That is, we can use @BeforeMethod/@AfterMethod(onlyForGroups = {"P2"}) instead of @BeforeMethod/@AfterMethod(onlyForGroups = {"P2"}, alwaysRun=true).

Please avoid this answer because I was not crystal clear about groups and onlyForGroups flag and how and when to use these flags. So, I recommend to use the easy solution given by PDHide, because it gives a more clearer explanation about the difference between groups and onlyForGroups flags and how and when to use them.

Related