Hacktoberfest 2026: những issue maintainer đã đánh dấu cho tháng Mười, đang mở và phù hợp người mới. Xem issue Hacktoberfest

No such session exception showing up

Đang mở
#1,628 3 bình luận 0 reaction 0 người được giao Xem trên GitHub

Maintainer thường phản hồi trong vòng 1 ngày

Chưa có ai nhận issue này.

Đánh giá

Độ khó
4/5
Thời gian dự kiến
3-5 ngày
Mức phù hợp với người mới
25/100
Loại issue
Lỗi
Độ rõ ràng
Cần làm rõ
Mức độ hoạt động
Ít trao đổi
Công nghệ
android, java
Lĩnh vực
mobile-dev, testing

Hướng nghiên cứu

Bắt đầu bằng cách so sánh vòng đời của BaseClass khi chạy toàn bộ suite với khi chạy riêng lẻ từng test, sau đó theo dõi SetupData.setParameters, AreaParameters và DataProviders.stimulationTestData. Tái hiện lỗi bằng các phiên bản Android và Appium được cung cấp, đồng thời kiểm tra thời điểm driver bị thoát hoặc thay thế. Được xem là hoàn tất khi test hướng dữ liệu hoàn thành trong toàn bộ suite mà không có null-session exception.

Do mô hình lập chỉ mục viết ra từ nội dung của issue.

Mô tả

The problem

I am trying to run a test class in a suite. The class that is giving the error is running a data driven test. The beforeMethod in the test runs fine, but for some reason the test fails as soon as it enters the @Test and tries setting a parameter in my Android Mobile test. This problem is consistent and only happens when i run the entire suite of classes. If I run the above mentioned class individually, it runs fine.

Environment

  • Appium version (or git revision) that exhibits the issue: 6.1.0
  • Desktop OS/version used to run Appium: Windows10
  • Node.js version (unless using Appium.app|exe): v12.18.2
  • Npm or Yarn package manager: 6.14.5
  • Mobile platform/version under test: Android 10.0
  • Real device or emulator/simulator: Real Device
  • Appium CLI or Appium.app|exe: Appium cli

Details

Error is as follows:

[ERROR] 2022-01-08 09:54:28 framework.Listeners.ExecutionListener 160 onTestFailure - Error type : 
**org.openqa.selenium.NoSuchSessionException: Session ID is null. Using WebDriver after calling quit()?**
Build info: version: '3.141.59', revision: 'e82be7d358', time: '2018-11-14T08:17:03'
System info: host: 'N-PF2JP03M', ip: '172.22.64.1', os.name: 'Windows 10', os.arch: 'amd64', os.version: '10.0', java.version: '1.8.0_281'
Driver info: driver.version: AppiumDriver
	at org.openqa.selenium.remote.HttpCommandExecutor.execute(HttpCommandExecutor.java:125) ~[selenium-remote-driver-3.141.59.jar:?]
	at io.appium.java_client.remote.AppiumCommandExecutor.execute(AppiumCommandExecutor.java:231) ~[java-client-6.1.0.jar:?]
	at org.openqa.selenium.remote.RemoteWebDriver.execute(RemoteWebDriver.java:552) ~[selenium-remote-driver-3.141.59.jar:?]
	at io.appium.java_client.DefaultGenericMobileDriver.execute(DefaultGenericMobileDriver.java:46) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.AppiumDriver.execute(AppiumDriver.java:1) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.HasSessionDetails.getSessionDetails(HasSessionDetails.java:39) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.HasSessionDetails.getSessionDetail(HasSessionDetails.java:56) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.HasSessionDetails.isBrowser(HasSessionDetails.java:86) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.AppiumDriver.isBrowser(AppiumDriver.java:271) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.lambda$0(WebDriverUnpackUtility.java:87) ~[java-client-6.1.0.jar:?]
	at java.util.Optional.map(Unknown Source) ~[?:1.8.0_281]
	at io.appium.java_client.pagefactory.utils.WebDriverUnpackUtility.getCurrentContentType(WebDriverUnpackUtility.java:83) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.pagefactory.AppiumElementLocator.getBy(AppiumElementLocator.java:90) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.pagefactory.AppiumElementLocator.findElement(AppiumElementLocator.java:117) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.pagefactory.interceptors.InterceptorOfASingleElement.intercept(InterceptorOfASingleElement.java:60) ~[java-client-6.1.0.jar:?]
	at io.appium.java_client.android.AndroidElement$$EnhancerByCGLIB$$b598166c.clear(<generated>) ~[java-client-6.1.0.jar:?]
	at framework.Screens.Patient.Sessions.CommonComponents.Area.AmplitudeControls.setAmplitude(AmplitudeControls.java:42) ~[test-classes/:?]
	at framework.commonUtilities.DataProvider.SetupData.setParameters(SetupData.java:32) ~[test-classes/:?]
	at com.tp.tp397_v2.Procedure4.TP397_Procedure4_Section08.execute_SNSConfiguredLeadProgram(TP397_Procedure4_Section08.java:160) ~[test-classes/:?]
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_281]
	at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_281]
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_281]
	at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_281]

I tried printing out the session ID i get from my driver at various places to find where its getting set to null, but i am not seeing it set to null anywhere:

	@BeforeMethod
	public void BeforeMethod(Method method, Object[] testData){
		//Set testName for each testcase
		log.info("\n******************************************************\n"
				+ "BeforeMethod called from TP397_Procedure4_Section08\n******************************************************\n");

	
		for(String str : testData[0].toString().split(","))
		{
			if(str.contains("TestID=")) {
				testName.set(method.getName() + "_" + str.split("=")[1]);
				break;
			}
		}

		//If CP is on login screen in case of a test failure OR for the very first execution
		//Login to CP, search and select patient Rosa.
		if(cpApp.Login.isVisible(cpApp.Login.clinicLogo, "txtClinicName")) {
			cpApp.Login.Login(cpAppProps.Passcode);
			cpApp.MyPatients.Search(patient.PatientName);
			cpApp.MyPatients.EnterFirstPatient();

			//From Sessions tab, create an OR session
			cpApp.Patient.TapSessions();
		}
		//Successive executions: CP is on OR Session screen.
		else {
			try{
				//For valid stimulation scenarios
				if(ORScreen.isStimulationActive()) { }
			}catch(Exception e) { }

			ORScreen.TapDone();
		}
		cpApp.Patient.waitForVisibilityOf(cpApp.Patient.sessionsTab, "sessionsTab");
		cpApp.Patient.Sessions.AddSession();
		cpApp.Patient.waitForVisibilityOf(cpApp.Patient.Sessions.ORSessionButton, "btnORSession");
		cpApp.Patient.Sessions.ChooseORSession();
		ORScreen.isDisplayed(patient.ClinicalIndication);
System.out.println("Session id in execute_SNSConfiguredLeadProgram @BeforeMethod is: " + driver.getSessionId());
	}

	@SuppressWarnings("unlikely-arg-type")
	@FrameworkAnnotation(author = { "RShah" }, deviceType="ETM1")
	@Test (description="Data-driven Test for SNS Configured Lead Program", dataProvider="stimulationTestData", dataProviderClass=DataProviders.class)
	public void execute_SNSConfiguredLeadProgram(Map<String, String> data) {	
		//Test ID which are covered in this test
		//TP397-025
		//TP397-026
		//TP397-027
		//TP397-028
		//TP397-029
		//TP397-030
		//TP397-031
		//TP397-032
		//TP397-033
System.out.println("Session id in execute_SNSConfiguredLeadProgram @Test (1) is: " + driver.getSessionId());
			log.info("The parameters used for this test are: \n" + data);
			ExtentLogger.logInfo("The parameters used for this test are: <br>" + data);
System.out.println("Session id in execute_SNSConfiguredLeadProgram @Test (2) is: " + driver.getSessionId());			
			ResultWriterParams.testCaseId = data.get("TestID");
			ResultWriterParams.acceptanceCriteria = String.format("Test CP Log with following parameters %s", programParameters);
			NTestCase testID = new NTestCase(ResultWriterParams.testCaseId, TP_ID);
System.out.println("Session id in execute_SNSConfiguredLeadProgram @Test (3) is: " + driver.getSessionId());
			if(data.get("TestType").toLowerCase().matches("configuredlead_valid")) {
				//Set OR Session parameters according to datasheet
				ExtentLogger.logInfo("Set OR Session parameters according to datasheet");
System.out.println("Session id in execute_SNSConfiguredLeadProgram @Test (4) is: " + driver.getSessionId());
				SetupData.setParameters(DataProviderType.OR_SESSION_DATA, data);

Point it fails at is SetupData.setParameters(DataProviderType.OR_SESSION_DATA, data);

The relevant portion where failure occurs in my SetupData class is as follows:


public class SetupData {
	private static AreaParametersComponent AreaParameters = new AreaParametersComponent();
	private static ORSessionScreen ORScreen= new ORSessionScreen();
	
	
	//From sessionType figure out the workbook to look at for test data
	static Map<String, String> WorkBookName = new HashMap<String, String>() {{
			  put("TP397_ORSession", TestDataConstants.OR_STIMULATION_TESTDATA_FILE);
			  put("TP368_programmingSession", TestDataConstants.STIMULATION_TEST_DATA_FILE);		
	}};
	
	//Setup data 
	public static void setParameters(DataProviderType dataType, Map<String, String> data) {
		switch(dataType) {
			case PATIENT_DATA:
				//Do patient data related setup
			case OR_SESSION_DATA:
				//Method to set OR Session parameters according to data from Stimulation dataSheets
				//Data is received as a HashMap argument
				AreaParameters.Amplitude.setAmplitude(data.get(TestData.ORSessionData.OR_Amplitude));
				AreaParameters.PulseWidth.setPulseWidth(data.get(TestData.ORSessionData.OR_PulseWidth));
				AreaParameters.Rate.setRate(data.get(TestData.ORSessionData.OR_ETX_Rate));
				setElectrodes(data);
							
			case PROGRAMMING_SESSION_DATA:
				//Do programming session related setup
		}
	}

My Dataproviders class is as follows:

public class DataProviders {
	private Logger log = LogManager.getLogger(this.getClass());
	private static String worksheet;
	private static String testType_String;
	private static String Tp_Id;
	
	
	public static void setTestParameters(String workSheetName, String testTypeString, String TP_ID) {
		worksheet = workSheetName;
		testType_String = testTypeString;
		Tp_Id = TP_ID;
	}
	
	/*
	 * DataProvider which converts the excel data to a hashmap and returns hashmap as a two-dimensional object array
	 * that @Test tests can use to iterate over
	 */
	@DataProvider
	public static Object[][] stimulationTestData(Method method) {
		List<String> testIDs;
		int iTestCaseRow;
		
		//Create new results arraylist
		List<Map<String, String>> results = new ArrayList<>();
		
		try {
			ExcelUtils.setExcelFile(SetupData.WorkBookName.get(Tp_Id), worksheet);
			
		    // Fetching the TestCase ID's related to particular TestType
		 	testIDs = ExcelUtils.getAllTestIDListForTestType(testType_String, 1, 2);
		 	System.out.println(testIDs);
		 				
		    //Only get rows that belong to the testID's
		 	for(String testID:testIDs) {
			 	// Getting the Test Case row which contains the testID
		 		try {
					iTestCaseRow = ExcelUtils.getRowContains(testID,2);

					//Get keys from header row (Row 1) and 
					List<String> keys = ExcelUtils.getValuesInSpecificRow(1);			
			 		List<String> values = ExcelUtils.getValuesInSpecificRow(iTestCaseRow);
			 		
			 		results.add(ExcelUtils.transform(keys, values));
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				} 	 				 		
	 		}
		} catch (Exception e1) {
			// TODO Auto-generated catch block
			e1.printStackTrace();
		}
	 	
	 	return ExcelUtils.asTwoDimensionalArray(results);	
	}	
}

My Base class is as follows (Renamed for security reasons):

@Listeners({ExecutionListener.class, ExtentListener.class})
public abstract class BaseClass implements ITest{

	protected static ResultWriterCSV resultWriter;
	private static Runtime runTime = Runtime.getRuntime();
	private static Boolean setupComplete = false;

	protected static AppiumDriver<MobileElement> driver;
	private AppiumDriverLocalService service;
	
	public static ClinicianProgrammer cpApp;
	public static TabletIO tablet;
	private static DesiredCapabilities caps;
	protected Logger log = LogManager.getLogger(this.getClass());		
	protected ThreadLocal<String> testName = new ThreadLocal<>();
	private LoadPropertiesFile loadPropFile;
	private static File appium_logfile_folder;
	
	@BeforeSuite
	public void timestamp_AppiumLogs_Folder(ITestContext ctx) {
		//If appium_logfile_folder exists from previous run, timestamp it
		appium_logfile_folder = new File(TestDataConstants.APPIUM_LOGFILE_LOCATION + "/" + ctx.getSuite().getXmlSuite().getName());
		String fileName = new SimpleDateFormat("yyyy-MM-dd-HH-mm'.csv'").format(new Date());
		
		if(appium_logfile_folder.exists()) {
			appium_logfile_folder.renameTo(new File(appium_logfile_folder + "-" + fileName));
			appium_logfile_folder.delete();
	    }
	}
	
	@BeforeTest
	public void setup(ITestContext ctx) {	
		setupComplete = false;
		resultWriter = ResultWriterCSV.getInstance();
		
		try {
			runTime.exec("adb shell am force-stop 'CP.Android'");
			
		} catch (IOException e) {
			e.printStackTrace();
		}
		
		//Create output folder within the outputs/AppiumLogs folder with TP name and procedure name 
		if(!appium_logfile_folder.exists()) {
			appium_logfile_folder.mkdir();
		}
	}
	
	@Parameters({"deviceName","platformVersion", "portNumber"})
	@BeforeClass
	public void initialize( String deviceName, String platformVersion, String portNumber) throws MalformedURLException, WebDriverException{
		try {
				log.info("BeforeClass from BaseClass");
				//Start Appium Service
				if(checkIfServiceIsRunning(Integer.parseInt(portNumber)))
					stopAppiumService();
				
				try {
					startAppiumService(portNumber, this.getClass().getSimpleName());
				} catch (Exception e) {
					e.printStackTrace();
				}
				
				//Set Appium driver capabilities
				loadPropFile = new LoadPropertiesFile(System.getProperty("user.dir")  + "\\framework.properties");
				loadPropFile.loadPropertiesFile();
				caps = new DesiredCapabilities();

				caps.setCapability("platformName", loadPropFile.getProperty("appium.platformName"));
				caps.setCapability("newCommandTimeout", loadPropFile.getProperty("appium.newCommandTimeout"));
				caps.setCapability("resetKeyboard", loadPropFile.getProperty("appium.resetKeyboard"));
				caps.setCapability("autoGrantPermissions", loadPropFile.getProperty("appium.autoGrantPermissions"));
				caps.setCapability("disableAndroidWatchers", true);
				caps.setCapability("skipUnlock", true);
				caps.setCapability(MobileCapabilityType.PLATFORM_VERSION, platformVersion);
				caps.setCapability(MobileCapabilityType.UDID, deviceName);
				caps.setCapability(AndroidMobileCapabilityType.APP_PACKAGE, loadPropFile.getProperty("appium.appPackage"));
				caps.setCapability(MobileCapabilityType.AUTOMATION_NAME, loadPropFile.getProperty("appium.automationName"));
				caps.setCapability(AndroidMobileCapabilityType.APP_ACTIVITY, loadPropFile.getProperty("appium.appActivity"));	
				caps.setCapability(MobileCapabilityType.NO_RESET, loadPropFile.getProperty("appium.dontStopAppOnReset"));	
				
				log.info("Starting Appium driver...");
				
				//Start Appium driver
				driver = new AppiumDriver<MobileElement>(new URL("http://127.0.0.1:" + portNumber + "/wd/hub"), caps);
System.out.println("Session id in BaseClass @BeforeClass is: " + driver.getSessionId());
				log.info("Appium driver started...");
				cpApp = new ClinicianProgrammer();
				tablet = new TabletIO();
		} catch (WebDriverException e) {			
			try {
				log.info("Retrying Appium driver start...");
				driver = new AppiumDriver<MobileElement>(new URL("http://127.0.0.1:" + portNumber + "/wd/hub"), caps);
			}catch(WebDriverException we) {
				log.error("Error starting Appium driver..." + we);
				we.printStackTrace();
				throw new WebDriverException();
			}
		} catch (MalformedURLException e) {		
			log.error("Error starting Appium driver..." + e.getMessage());
			log.error("Error starting Appium service...: full stack trace follows:", e);
			e.printStackTrace();
			throw new MalformedURLException();
		}
	}
	
	public static WebDriver getDriver() {
		return driver;
	}
	
	/*Here alwaysRun is set to true because in normal circumstances BeforeMethod is skipped if BeforeClass fails
	  we want to set the TestName to be set even if the BeforeClass fails. Setting alwaysRun to true ensures
	  that the testName will always be set. This prevents bug in extentListener which was taking the previous testcase Name
	  instead of the current one while logging in Extent Reports
	  */
	@BeforeMethod(alwaysRun=true)
	public void setUpTest(Method method, Object[] testData, ITestContext ctx) {	
		log.info("BeforeMethod from BaseClass");
		try {
			Map<String,String> map = new HashMap<String,String>();
			
			 //Updates names of testcases that use DataProviders
			if (testData.length > 0) {
				 //Code used for dataproviders from excel sheets that contain TestID
				String[] entries = testData[0].toString().split(",");
				if(entries.length>1) {
					for(String entry:entries) {
						map.put(entry.split("=")[0].trim(), entry.split("=")[1].trim());
					}
			    testName.set(method.getName() + "_" + map.get("TestID"));
			    ctx.setAttribute("testName", method.getName() + "_" + map.get("TestID"));
				}
				else {
					//Code used for dataproviders that have single entry and no TestID's, viz create_patient
					testName.set(method.getName() + "_" + testData[0].toString());
				    ctx.setAttribute("testName", method.getName() + "_" + testData[0].toString());
				}
			 } else {
				 testName.set(method.getName());
				 ctx.setAttribute("testName", method.getName());
			 }
	
	
			 log.info("Testname in BaseClass is: " + ctx.getAttribute("testName"));
			 
			//Also check if app is already running. Helpful in conditions where app shutsdown in middle of any testcase though setup was completed successfully
			if (!setupComplete && driver!=null){
				log.info("Relaunching app due to setup incomplete or driver==null...");
				try {
					driver.launchApp();
					beforeEachTestMethod();
				}catch(Exception e) {
					e.printStackTrace();
					throw new Exception();
				}
			}
			setupComplete=true;
		}catch(Exception e) {e.printStackTrace();}
	}
	
	@Override
	public String getTestName() {
		return testName.get();
	}
	
	public void beforeEachTestMethod()
	{
		//This should be overridden.
	}
	
	@AfterMethod
	public void afterMethod(ITestResult result) {
		/*
		 	App force shutsdown under two conditions:
				1) If setup did not complete successfully in the @Before method
				2) If setupComplete = true, but test fails, check the custom restart flag and then reset the setupComplete flag shutdown app
						By default restart flag is set to true
		*/


		if(Globals.restartAppFlag) {		
			log.info("\n**********************************************\n"
					+ "AfterMethod called from BaseClass\n**********************************************\n");
System.out.println("Session id in BaseClass @AfterMethod is: " + driver.getSessionId());
			if ((!setupComplete) || ((setupComplete==true && Globals.testFailedStatus==true))){
				log.info("CP App will be shutdown due to above failure");
				//driver.quit();
				setupComplete = false;
			}
		}
		
	}
	
	@AfterClass(alwaysRun=true)
	public void afterClass() {		
		log.info("\n*******************************\n"
				+ "After class cleanup executed from NTestSection\n*******************************\n");
		//Set setupComplete to false so that @BeforeMethod runs before each class
System.out.println("Session id in NTestSection @AfterClass is: " + driver.getSessionId());
		driver.quit();
System.out.println("Session id in NTestSection @AfterClass is: " + driver.getSessionId());
		setupComplete = false;
		stopAppiumService();		
	}
	
	@AfterTest
	public void cleanup() {
//		log.info("\n*******************************\n"
//				+ "After test cleanup executed\n*******************************\n");	
	}	
	
	public void startAppiumService(String portNumber, String className) throws Exception {
		log.info("Starting Appium service. /n Logs will be stored at: " + appium_logfile_folder + "/appium_"+ className + ".log");
		File appium_logfile = new File(appium_logfile_folder + "\\appium_"+ className + ".log");
		
		try {
		AppiumServiceBuilder builder = new AppiumServiceBuilder();
		builder.withIPAddress("127.0.0.1");
		builder.usingPort(Integer.parseInt(portNumber));
		builder.withLogFile(appium_logfile);
		//builder.withArgument(GeneralServerFlag.LOG_LEVEL, LogLevel.ERR.toString());
		service = AppiumDriverLocalService.buildService(builder);
		service.start();
		service.clearOutPutStreams();
		log.info("Service has been started with port number " + portNumber);
		}catch(Exception e) {
			log.error("Error starting Appium service...");
			try {
				log.info("Retrying Appium service start");
				service.start();		
				service.clearOutPutStreams();
			}catch(Exception ae) {
				log.error("Error starting Appium service...: full stack trace follows:", ae);
				throw new Exception();
			}
		}
	}
	
	public void stopAppiumService() {

		Runtime runtime = Runtime.getRuntime();
		try {
			runtime.exec("taskkill /F /IM node.exe");
			runtime.exec("taskkill /F /IM cmd.exe");
			log.info("Appium service stopped...");
		} catch (IOException e) {
			log.error("Could not stop Appium service...");
			e.printStackTrace();
		}
	}
	
	public static boolean checkIfServiceIsRunning(int port) {
		boolean isServerRunning = false;
		ServerSocket serverSocket;
		try {
			serverSocket = new ServerSocket(port);
			serverSocket.close();
		}catch(IOException e) {
			//If control comes here, then it means that the port is in use
			isServerRunning = true;
		}finally {
			serverSocket = null;
		}
		if(isServerRunning)
			System.out.println("Appium service is already running on port: " + port);
		return isServerRunning;
	}
}

Link to Appium logs

(https://gist.github.com/skhandekar1/e4d300b1ae9619009191c0398e948b4d)

Ngôn ngữ chính
Java
Star
1.3k
Fork
755
Merge trung bình
5 ngày 14 giờ
Pull request đã merge (30 ngày)
8

Chuẩn bị môi trường

  • Không có Dockerfile hay tệp Docker Compose
  • Có mẫu pull request
  • Không có hướng dẫn đóng góp

Bắt đầu từ đâu

  1. Đọc hết issue, rồi đọc hướng dẫn đóng góp của dự án.
  2. Bình luận trên issue rằng bạn sẽ nhận — tránh hai người làm cùng một việc.
  3. Fork repository và làm thay đổi trên một nhánh.
  4. Mở pull request có tham chiếu số hiệu của issue.

Issue khác của appium/java-client

Tất cả issue của appium/java-client

Issue tương tự

Thêm issue về Java

Nhận issue mới trong hộp thư của bạn

Bản tóm tắt ngắn những issue GitHub phù hợp với người mới.