I am using IRetryAnalyzer interface to run failed test cases again. It works fine if I have only one Test in my TestNG XML file, however if I have multiple tests in my XML file it works only for the first test.
Root Cause: the retryCount for second test is set to 1, I am not sure how to reset it.
Existing open issue:
https://github.com/cbeust/testng/issues/1241
RetryAnalyzer.java
public class RetryAnalyzer implements IRetryAnalyzer {
private int retryCount = 0;
private int maxRetryCount = 1;
public boolean retry(ITestResult result) {
if (retryCount < maxRetryCount) {
retryCount++;
return true;
}
return false;
}
}
AnnotationTransformer.java
public class AnnotationTransformer implements IAnnotationTransformer {
public void transform(ITestAnnotation annotation, Class testClass, Constructor testConstructor, Method testMethod) {
annotation.setRetryAnalyzer(RetryAnalyzer.class); //to enable for all the methods.
}
}
TestNG.xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="BrowserStack" >
<listeners>
<listener class-name="uk.co.gaurang.libs.ResultListener" />
<listener class-name="uk.co.gaurang.libs.AnnotationTransformer" />
</listeners>
<test name="IPhone6S">
<classes>
<class name="uk.co.gaurang.tests.Demo"/>
</classes>
</test>
<test name="IPhone6SPlus">
<classes>
<class name="uk.co.gaurang.tests.Demo"/>
</classes>
</test>
</suite>
Related
I want to create a Splash screen and show it as long as the authentication state of the user gets determined. I have a global singleton called AuthStateController which holds my state and some extra functions.
But because the installSplashScreen function is outside of a composable I can't use Koin to inject the AuthStateController class to get access to my loading state.
Below is my MainActivity with all my Koin modules. And the installSplashScreen function.
class MainActivity : ComponentActivity() {
// not allowed because outside of Composable
private val authStateController: AuthStateController by inject()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
startKoin {
androidLogger(if (BuildConfig.DEBUG) Level.ERROR else Level.NONE)
androidContext(this#MainActivity)
modules(listOf(appModule, networkModule, viewModelModule, interactorsModule))
}
installSplashScreen().apply {
setKeepVisibleCondition {
// need AuthStateController instance to determine loading state
authStateController.state.value.isLoading
}
}
setContent {
M3Theme {
SetupNavGraph()
}
}
}
}
}
This is the Koin module that provides my AuthStateController class:
val appModule = module {
single { AuthStateController(get()) }
}
And this is my AuthStateController class which holds my state and some extra functions:
class AuthStateController(
private val getMeInterceptor: GetMeInterceptor
) {
val state: MutableState<AuthState> = mutableStateOf(AuthState())
fun fetchMe() {
val me = getMeInterceptor.execute().collect(CoroutineScope(Dispatchers.IO)) { dataState ->
dataState.data?.let {
state.value =
state.value.copy(profile = it, isAuthenticated = true, isLoading = false)
}
}
}
init {
val token = settings.getString(Constants.AUTH_TOKEN)
if (token.isNotBlank()) {
fetchMe()
state.value = state.value.copy(authToken = token)
}
}
}
How can I get access to the singleton created with Koin inside the MainActivity and use it inside the installSplashScreen function?
Edit
Android Manifest:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="com.example.sessions_clean.android">
<uses-permission android:name="android.permission.INTERNET" />
<application
// app crashes when adding line below
android:name=".MainApplication"
android:allowBackup="false"
android:supportsRtl="true"
android:theme="#style/Theme.App.Starting"
android:usesCleartextTraffic="true">
<activity
android:name=".MainActivity"
android:exported="true"
android:theme="#style/Theme.App.Starting">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
When I add android:name to the already existing application tag the App crashes instantly.
But when I create a new application tag for the new MainApplication I get errors in the IDE like Attribute android:allowBackup is not allowed here
I think you can startKoin inside the Application
MainApplication.kt
class MainApplication : Application() {
override fun onCreate() {
super.onCreate()
startKoin {
...
}
}
}
AndroidManifest.xml
<manifest ...>
<application
android:name=".MainApplication"
...>
...
</application>
</manifest>
I am implementing groups in the testng test suite.When I run my testng suite suite,it runs only the 'FireFox' test and when I put the tag in 'Firefox' test
it runs the 'IE' test.Kindly let me know what can be the reason for this??
<groups>
<run>
<include = "smoke"/>
</run>
</groups>
<classes>
<class name = "com.asw.beginner.tests.NewTest"/>
</classes>
</test>
<test name = "FireFox" allow-return-values = "true">
<parameter name = "browser" value = "FF"/>
<classes>
<class name = "com.asw.beginner.tests.NewTest"/>
</classes>
</test>
Define your test as following:
public class Test1 {
#Test(groups = { "functest" })
public void testMethod1() {
}
#Test(groups = {"functest", "checkintest"} )
public void testMethod2() {
}
#Test(groups = { "checkintest" })
public void testMethod3() {
}
}
Then you can use xml file as following
<test name="Test1">
<groups>
<run>
<include name="functest"/>
</run>
</groups>
<classes>
<class name="example1.Test1"/>
</classes>
</test>
Above test will only run the method with group functest.
You can read more about testng from Official testng documatation
Following is example java code
import org.testng.Assert; import org.testng.annotations.Test;
public class GroupTestExample { String message = ".com"; MessageUtil messageUtil = new MessageUtil(message);
#Test(groups = { "functest", "checkintest" })
public void testPrintMessage() {
System.out.println("Inside testPrintMessage()");
message = ".com";
Assert.assertEquals(message, messageUtil.printMessage()); }
#Test(groups = { "checkintest" })
public void testSalutationMessage() {
System.out.println("Inside testSalutationMessage()");
message = "tutorialspoint" + ".com";
Assert.assertEquals(message, messageUtil.salutationMessage()); }
#Test(groups = { "functest" })
public void testingExitMessage() {
System.out.println("Inside testExitMessage()");
message = "www." + "tutorialspoint"+".com";
Assert.assertEquals(message, messageUtil.exitMessage()); } }
following is Testng.xml file
<groups>
<run>
<include name = "functest" />
</run>
</groups>
<classes>
<class name = "GroupTestExample" />
</classes>
</test> </suite>
// Testng xml
<test name="Test1" preserve-order ="true">
<parameter name="deviceName_" value="aaaa"/>
<classes>
<class name="Test">
<methods>
<include name="methodName"/>
</methods>
</class>
</classes>
</test>
// Can i pass parameters at method level like i passed deviceName at test level
Actually, parameters on method level exists. Here is an example:
<suite name="my-suite" verbose="1">
<test name="my-test">
<classes>
<class name="testng.ex1.TestParams">
<methods>
<include name="m1">
<parameter name="key1" value="val1"/>
<parameter name="key2" value="val2"/>
</include>
<include name="m2">
<parameter name="key1" value="valA"/>
<parameter name="key2" value="valB"/>
</include>
</methods>
</class>
</classes>
</test>
</suite>
and the test class is,
package testng.ex1;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class TestParams {
#Test
#Parameters({ "key1", "key2" })
public void m1(String key1, String key2) throws Exception {
System.out.println(key1 + ", " + key2);
}
#Test
#Parameters({ "key1", "key2" })
public void m2(String key1, String key2) throws Exception {
System.out.println(key1 + ", " + key2);
}
}
another approach is to use a data-provider that fetches the keys from testng.xml. See example:
<suite name="my-suite" verbose="1">
<test name="my-test">
<classes>
<parameter name="keys" value="key1,key2,key3,key4" />
<class name="testng.ex2.TestParams" />
</classes>
</test>
</suite>
The test calss,
package testng.ex2;
import java.util.Arrays;
import java.util.List;
import org.testng.ITestContext;
import org.testng.annotations.DataProvider;
import org.testng.annotations.Parameters;
import org.testng.annotations.Test;
public class TestParams {
#Test(dataProvider = "dp")
public void m1(Employee e) throws Exception {
System.out.println("name: " + e.getName() + ", age: " + e.getAge());
}
#DataProvider(name = "dp")
#Parameters("keys")
public Object[][] createData(ITestContext ctx) {
String keysString = ctx.getCurrentXmlTest().getLocalParameters().get("keys");
List<String> keys = Arrays.asList(keysString.split(","));
Object[][] result = new Object[keys.size()][1];
for (int i = 0; i < keys.size(); i++) {
String key = keys.get(i);
result[i] = new Object[] { new Employee(key) };
}
return result;
}
}
The employee class,
package testng.ex2;
public class Employee {
private final String name;
private final int age;
public Employee(String key) {
// use 'key' to lookup employee in database
name = key + "_name"; // dummy value
age = 41; // dummy value
}
String getName() {
return name;
}
int getAge() {
return age;
}
}
you can get the parameter in the before method as given below,
#BeforeMethod
#Parameters({ "key1", "key2" })
public void beforem1(String key1, String key2){
System.out.println(key1 + ", " + key2);
}
Code is Grouping in TESTNG
package testNG_annot;
import org.testng.annotations.BeforeMethod;
import org.testng.annotations.Test;
public class TestNG_grp1
{
#BeforeMethod
public void CarBM() {
System.out.println("CarBM");
}
*** // Created group car and Two wheeler//***
#Test(groups = { "Car" })
public void Sedan1() {
System.out.println("Test1-Verna");
}
#Test(groups = { "Car" })
public void Sedan2() {
System.out.println("Test2-BMW");
}
#Test(groups = { "TwoWheeler" })
public void Scooter1() {
System.out.println("Test3-ScootyPep");
}
#Test(groups = { "TwoWheeler" })
public void aScooter2() {
System.out.println("Test4-TVS");
}
}
suite.xml
<?xml version="1.0" encoding="UTF-8"?>
<suite name="grp11">
<test name="group1">
<gropus>
<run>
<include name="Car"/>
</run>
</gropus>
<classes>
<class name="testNG_annot.TestNG_grp1"/>
</classes>
</test>
</suite>
Your spelling for groups tag is wrong. Change the spelling and run it again.
<groups>
<run>
<include name="Car"/>
</run>
</groups>
Form the testng.xml file as below format. Run it as testng test and you will get your test running.
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
<suite name="Suite1">
<test name="Test" >
<classes>
<class name="testNG_annot.TestNG_grp1" />
</classes>
</test>
</suite>
Keep this on top in your xml
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd" >
I have a test suite and I want to run tests form XML file one-by-one. But when I'm running it, it runs all TCs at the same time (I have 3 open browsers at the same time).
My XML:
<suite name="TestingSuite" preserve-order="true" parallel="false" verbose="10">
<test name="Test1">
<classes>
<class name="guiAndFunctianal.LoginFail" />
<class name="guiAndFunctianal.LoginAsManager" />
<class name="guiAndFunctianal.CreateUserTest" />
</classes>
</test>
</suite>
My TCs looks like this:
public class LoginFail extends AbstractTest{
# BeforeTest
public void openBrowser() {
openBrowserFireFoxAllTcs();
}
# Test
public void main (){
}
# AfterTest
public void quit() {
driver.quit(); }
AbstractTest
public class AbstractTest {
WebDriver driver = new FirefoxDriver();
WebDriverWait wait = new WebDriverWait(driver, 10);
public void openBrowserFireFoxAllTcs() {
driver.get("some URL");
}
I assume you want sequential execution. Open a browser>finish testing>close browser and then repeat the same for other browsers. If that's case I would do the following:
TestNG.XML
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE suite SYSTEM "http://testng.org/testng-1.0.dtd">
<suite name="Suite" junit="false" parallel="false" configfailurepolicy="skip" thread-count="5" skipfailedinvocationcounts="false" data-provider-thread-count="10" group-by-instances="false" preserve-order="true" allow-return-values="false">
<test name="firefox" junit="false" skipfailedinvocationcounts="false" preserve-order="true" group-by-instances="false" allow-return-values="false">
<parameter name="browser" value="firefox" />
<classes>
<class name="com.github.tests.GitHubHomePageTests" />
</classes>
</test>
<test name="ie" junit="false" skipfailedinvocationcounts="false" preserve-order="true" group-by-instances="false" allow-return-values="false">
<parameter name="browser" value="ie" />
<classes>
<class name="com.github.tests.GitHubHomePageTests" />
</classes>
</test>
<test name="chrome" junit="false" skipfailedinvocationcounts="false" preserve-order="true" group-by-instances="false" allow-return-values="false">
<parameter name="browser" value="chrome" />
<classes>
<class name="com.github.tests.GitHubHomePageTests" />
</classes>
</test>
</suite>
How I instantiate the drivers:
package com.github.tests;
import org.openqa.selenium.WebDriver;
import org.openqa.selenium.chrome.ChromeDriver;
import org.openqa.selenium.firefox.FirefoxDriver;
import org.openqa.selenium.ie.InternetExplorerDriver;
import org.testng.annotations.*;
public class BaseTest {
public WebDriver driver;
String url = "https://github.com/";
#Parameters("browser")
#BeforeClass
public void SetUpTests(String browser) {
if (browser.equalsIgnoreCase("firefox")) {
driver = new FirefoxDriver();
} else if (browser.equalsIgnoreCase("ie")) {
System.setProperty("webdriver.ie.driver", ".\\drivers\\IEDriverServer.exe");
driver = new InternetExplorerDriver();
} else if (browser.equalsIgnoreCase("chrome")) {
System.setProperty("webdriver.chrome.driver", ".\\drivers\\chromedriver.exe");
driver = new ChromeDriver();
}
//Navigate to url
driver.navigate().to(url);
//Maximize the browser window
driver.manage().window().maximize();
}
#AfterClass
public void CleanUpDriver() throws Exception {
// Quit current driver instance.
try {
driver.quit();
} catch (Exception ex) {
throw ex;
}
}
How the test run
package com.github.tests;
import com.github.pageobjects.GitHubLandingPage;
import org.testng.Assert;
import org.testng.annotations.Test;
public class GitHubHomePageTests extends BaseTest {#Test
public void ExploreLinkTest() {
String explorePageTitle = new GitHubLandingPage(driver)
.clickGitHubExplorePage()
.getGitHubExplorerPageTitle().trim();
System.out.println(explorePageTitle);
Assert.assertEquals(explorePageTitle, "Explore GitHub");
}
}
A global Github repo is available here
Try this:
<suite name="TestingSuite" preserve-order="true" thread-count="1" verbose="10">
<test name="Test1">
<classes>
<class name="guiAndFunctianal.LoginFail" />
</classes>
</test>
<test name="Test2">
<classes>
<class name="guiAndFunctianal.LoginAsManager" />
</classes>
</test>
<test name="Test3">
<classes>
<class name="guiAndFunctianal.CreateUserTest" />
</classes>
</test>
</suite>
Close your driver before quit:
# AfterTest
public void quit() {
driver.close()
driver.quit();
}