Dependency Attribute With @Test Annotation: As we learn the TestNG automation framework, we also learn new and exciting topics. In this post, we will discuss another important feature of TestNG: Dependency.
As we use TestNG as a unit testing framework, we don’t want the result of one test method to affect other test methods. But sometimes, we encounter situations where one test method depends on other tests.
For Example:
You want to send a mail to your dear one, and for that, if we take a look at the test case, then that should be something like this:
- Launch browser
- Open Gmail
- Sign in to Your Account
- Send email
If you see that all the operations should be performed in the mentioned order, otherwise your test script fails. So, in the above example, each test case depends on the other. If you change the functionality, then the required functionality will not work.
In this case, we need to maintain dependency between the test method or between scenarios in some order and execute them on the result of the previous method to save time.
To Handle such scenarios, TestNg provides two attributes: dependsOnMethod and dependsOnGroup. You can use these two attributes with @test annotation to achieve the dependency between the tests.
How to Use Dependency Attribute On Method Level
Things to Remember about dependsOnMethod:
- If you are executing the entire suite or class, the parent methods will always run first; after that, only the dependent methods will be executed.
- If you are only running the dependent test, then the parent method will be executed first, and the dependent test will be executed later.
- If the parent methods fail, the dependent test will not run and will be marked as skipped.
Below is the sample code to understand how dependsOnMethod is working at the method level
package com.softwaretestingo.testng.attributes; import org.testng.annotations.BeforeTest; import org.testng.annotations.Test; public class DependsOnMethods2 { @BeforeTest public void launchBrowser() { System.out.println("Browser Launched."); } @Test public void loadFacebookURL() { System.out.println("Facebook URL loaded."); } /* * registerOnFacebook depends on loadFacebookURL */ @Test(dependsOnMethods = {"loadFacebookURL"}) public void registerOnFacebook() { System.out.println("Register on Facebook."); } /* * postStatusOnFacebook depends on registerOnFacebook */ @Test(dependsOnMethods = {"registerOnFacebook"}) public void postStatusOnFacebook() { System.out.println("Post a status on Facebook."); } }
Output:
Browser Launched. Facebook URL loaded. Register on Facebook. Post a status on Facebook. =============================================== Default test Tests run: 3, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 3, Passes: 3, Failures: 0, Skips: 0 ===============================================
How does dependsOnGroup work in TestNG?
Above, we have seen how we can use the dependency on the method level, and now we will learn how to use dependency on the group level. Because when we are doing
testing according to the behavior, we are conducting different types of testing like smoke, integration, sanity, and regression.
As an automation tester, when we get a build first, we do some testing, and if the smoke testing is passed, we start another testing. Similarly, we must make a group for that supposed smoke group to do smoke testing.
If all the methods of the smoke group are passed, then only we should continue our testing process. In that case, we can use the dependsOnGroup attribute.
Some points to remember about dependsOnGroup:
- If you execute the entire suite or class, the parent groups will always execute first; after that, only the dependent groups will be run.
- If you are only running the dependent group, the parent groups will be executed first, and the dependent group will be executed later.
- If the parent group and test methods fail, the dependent group will not run and will be marked as skipped.
Sample Program:
package com.softwaretestingo.testng.attributes; import org.testng.annotations.Test; public class DependsOnGroup { // Test method belong to preSetupTestA @Test(groups= {"preSetupTestA"}) public void methodA() { System.out.println("MethodA"); } //Test method belong to preSetupTestA @Test(groups= {"preSetupTestA"}) public void methodB() { System.out.println("MethodB"); } // Test method belong to preSetupTestB @Test(groups= {"preSetupTestB"}) public void methodC() { System.out.println("MethodC"); } // Test method belong to preSetupTestB @Test(groups= {"preSetupTestB"}) public void methodD() { System.out.println("MethodD"); } // Test method which is dependent of other groups @Test(dependsOnGroups = {"preSetupTestB", "preSetupTestA"}) public void finalTest() { System.out.println("Final Test."); } }
Output:
MethodA MethodB MethodC MethodD Final Test. =============================================== Default test Tests run: 5, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 5, Passes: 5, Failures: 0, Skips: 0 ===============================================
Note: You can mention one or multiple groups at a time. Commas can separate those groups.
How to Use Regular Expression With DependsOnGroup?
During the use of dependsOnGroups, we have seen that we need to mention all the dependents on the group name in the dependent method. But if the group’s name is on a specific pattern, then we can say that it depends on group names with regular expressions. So that there is no need to mention all the group names one by one.
For Example:
package com.softwaretestingo.testng.attributes; import org.testng.annotations.Test; public class RegularExpressionsInDependsOnGroups { // Test belong to Group registration @Test(groups = "registration", priority= 1) public void signUp() { System.out.println("Signed Up"); } // Test belong to Group registrationStatus @Test(groups = "registrationStatus", priority= 2) public void verifyRegistration() { System.out.println("Registration Was successful"); } // Tests belong to group login @Test(groups = "login", priority= 3) public void logIn() { System.out.println("Logged In"); } // Tests belong to group loginStatus @Test(groups = "loginStatus", priority= 4) public void verifyLogIn() { System.out.println("Log In was successful."); } // This test is dependent on all above groups. You need to mention all group names explicitly here. @Test(dependsOnGroups = { "registration", "login", "registrationStatus", "loginStatus" }) public void purchaseSomething() { System.out.println("purchased Something"); } }
Output:
Signed Up Registration Was successful Logged In Log In was successful. purchased Something
If you saw the above code, you can say that we have mentioned all the group names, so it becomes complicated when there are a number of groups or adding or deleting a new group.
When adding or deleting, you need to change the group names, but the same thing we can handle easily with the pattern.
package com.softwaretestingo.testng.attributes; import org.testng.annotations.Test; public class RegularExpressionsInDependsOnGroups2 { // Test belong to Group registration @Test(groups = "userAccess_registration", priority= 1) public void signUp() { System.out.println("Signed Up"); } // Test belong to Group registrationStatus @Test(groups = "userAccess_registrationStatus", priority= 2) public void verifyRegistration() { System.out.println("Registration Was successful"); } // Tests belong to group login @Test(groups = "userAccess_login", priority= 3) public void logIn() { System.out.println("Logged In"); } // Tests belong to group loginStatus @Test(groups = "userAccess_loginStatus", priority= 4) public void verifyLogIn() { System.out.println("Log In was successful."); } // This test is dependent on all above groups. Since we have followed a naming pattern in group names, we can use regular expression with // dependsOnGroups. @Test(dependsOnGroups = { "userAccess_.*" }) public void purchaseSomething() { System.out.println("purchased Something"); } }
Output:
Signed Up Registration Was successful Logged In Log In was successful. purchased Something PASSED: com.software
Types Of Dependency On TestNG
Earlier in this post, we have seen how to create a dependency between methods. Now, we are learning various types of dependency on testNG & how to use that in your testing framework.
In TestNG, we have two types of Dependency:
Hard Dependency: In this type of dependency, if all the dependence on a method passes, then only the dependence on the method can run. Otherwise, it depends on the method invoked and marked as SKIP in the testNG report.
Soft Dependency: In this type of dependency, if some depend on failed methods, the dependent method will run. That means it does not rely on the result of the depends on methods. We can get the soft dependency by using the “alwaysRun=true” attribute with the @test annotation.
Hard Dependency On TestNG
When we implemented dependsOnMethod, we have seen if the parent method failed, the dependent method got skipped, but at that time, we didn’t know whether the skipped method was a failed method or not in the test.
For Example:
package com.softwaretestingo.testng.attributes; import org.testng.Assert; import org.testng.annotations.Test; public class HardDependeny { // Explicitly failing method on which Test2 is dependent @Test public void Test1() { System.out.println("I am Test1"); Assert.fail(); } // Test2 will not run as Test1 has failed. Test2 will be marked as skipped. @Test(dependsOnMethods= {"Test1"}) public void Test2() { System.out.println("I am Test2"); } }
Output:
I am Test1 FAILED: com.softwaretestingo.testng.attributes.HardDependeny.Test1 =============================================== Default test Tests run: 2, Failures: 1, Skips: 1 =============================================== =============================================== Default suite Total tests run: 2, Passes: 0, Failures: 1, Skips: 1 ===============================================
Soft Dependency On TestNG
If you want to run, the dependent method always runs irrespective of the result, depending on the method. Then, that type of dependency is called soft dependency, and we can achieve that by adding the alwaysRun=true attribute in the dependent method.
Sample Program:
package com.softwaretestingo.testng.attributes; import org.testng.Assert; import org.testng.annotations.Test; public class SoftDependeny { // Explicitly failing method on which Test2 is dependent @Test public void Test1() { System.out.println("I am Test1"); Assert.fail(); } // Test2 will run if Test1 has failed. Because we have used alwaysRun attribute. @Test(dependsOnMethods= {"Test1"}, alwaysRun= true) public void Test2() { System.out.println("I am Test2"); } }
Output:
I am Test1 I am Test2 PASSED: com.softwaretestingo.testng.attributes.SoftDependeny.Test2 FAILED: com.softwaretestingo.testng.attributes.SoftDependeny.Test1 =============================================== Default test Tests run: 2, Failures: 1, Skips: 0 =============================================== =============================================== Default suite Total tests run: 2, Passes: 1, Failures: 1, Skips: 0 ===============================================
ignoreMissingDependencies In TestNG
We have seen the hard dependency and soft dependency we can use with the existing depends on the method, but the thing about a scenario like:
Scenario 1:
How will you run your test, which depends on other tests and tests that do not always exist or need to be executed based on some conditions?
package com.softwaretestingo.testng.attributes; import org.testng.annotations.Test; public class IgnoreMissingDependencies { /* * This test method depends on another test method named "Test1" which does not exist. */ @Test(dependsOnMethods= {"Test1"}) public void Test2() { System.out.println("I am Test2"); } }
Output:
org.testng.TestNGException: com.softwaretestingo.testng.attributes.IgnoreMissingDependencies.Test2() depends on nonexistent method Test1
When you run the above class, you will get an exception where it is mentioned that “depends on the nonexistent method.”
Scenario 2:
How you run your test depends on another one marked false for the “enabled” attribute.
package com.softwaretestingo.testng.attributes; import org.testng.annotations.Test; public class IgnoreMissingDependencies2 { @Test(enabled= false) public void Test1() { System.out.println("I am Test1"); } /* * This test method depends on another test method named "Test1" which is not enabled. */ @Test(dependsOnMethods= {"Test1"}) public void Test2() { System.out.println("I am Test2"); } }
In the Second scenario also, you can say that you are getting an exception like the one below:
org.testng.TestNGException: com.softwaretestingo.testng.attributes.IgnoreMissingDependencies2.Test2() is depending on method public void com.softwaretestingo.testng.attributes.IgnoreMissingDependencies2.Test1(), which is not annotated with @Test or not included.
But, in this case, you can use the “ignoreMissingDependencies” attribute To run your tests even if the dependencies are missing or disabled.
package com.softwaretestingo.testng.attributes; import org.testng.annotations.Test; public class IgnoreMissingDependencies3 { @Test(enabled= false) public void Test1() { System.out.println("I am Test1"); } /* * This test method depends on another test method named "Test1" which is not enabled. */ @Test(dependsOnMethods= {"Test1"}, ignoreMissingDependencies= true) public void Test2() { System.out.println("I am Test2"); } }
Output:
I am Test2 PASSED: com.softwaretestingo.testng.attributes.IgnoreMissingDependencies3.Test2 =============================================== Default test Tests run: 1, Failures: 0, Skips: 0 =============================================== =============================================== Default suite Total tests run: 1, Passes: 1, Failures: 0, Skips: 0 ===============================================