记录java+testng运行selenium(四)--- 运行代码
涉及的文件有:
.\medical\BusinessFile.java :实例化excel及xml文件操作对象以及将list变成Map
.\medical\manual\business\LoginBusiness.java :通过放射获取元素路径及用例动作的执行(每个对应的test都应该有之相对应的business)
.\medical\manual\handles\LoginElement.java :元素对象路径定义类,后期元素对象的路径发生改变之后只需要修改相应的值即可。
及读取excel读取的数据返回到用例执行类中(excel读取可以放在LoginBusiness文件中)
.\medical\manual\user\TestUserLogin.java : test用例类
.\medical\manual\user\TestUserLogin.xml: test中定义的excel文件所在路径
一: 编写excel所在目录及sheet名
创建TestUserLogin.xml并编写以下内容
<?xml version="1.0" encoding="UTF-8"?> <data> <loginTest> <load>.\drivers\测试用例.xlsx</load> <sheetName>登录</sheetName> </loginTest> </data>
二:编写test执行类
创建TestUserLogin.java并编写以下代码
import java.util.Map; import org.testng.annotations.*; import medical.manual.business.LoginBusiness; import medical.manual.handles.LoginElement; public class TestUserLogin { private LoginBusiness lb; @BeforeMethod public void runDriveBrowser() { String filename = "hospital.ini"; this.lb = new LoginBusiness(filename); } @AfterMethod public void closeDrive() { lb.browser.closeBrowser(1000); } /** * dataProvider可以是定义的name名字也可以是函数名 * @param param 单行excel数据 */ @Test(description = "用户的登录", dataProvider = "getLoginData", dataProviderClass = LoginElement.class) public void loginTest(Map<?, ?> param) { lb.medicalRecords(param); } }
函数说明:
runDriveBrowser :每条用例执行时都重新创建浏览器对象,并把浏览器所在的ini文件当做参数传入到用例操作类中
closeDrive :用于关闭浏览器的操作,传入延迟时间主要用于延迟关闭操作
loginTest : 通过数据驱动的形式,只需要定义一个函数然后就可以执行同一个sheet下的用例(前提是用例结果相同)。
三:元素实现类
创建BusinessFile.java 并编写以下内容
package medical; import org.testng.Assert; import toolskit.documents.ReadExcel; import toolskit.documents.XmlUtil; import java.util.ArrayList; import java.util.List; import java.util.Map; /** * @ ClassName: medical * @ Author: DingDong * @ Date: 2019/10/21 16:25 * @ Version: 1.0 * @ desc: */ public class BusinessFile { public Object[][] dataProviderSource(String load,String sheetName){ ReadExcel re = new ReadExcel(); List<Map<String, String>> maps = re.readExcel(load, sheetName); Object[][] testData = mapsToArray(maps); return testData; } public List<Map<String, String>> getXmlData(String methodName,String xmlPath){ List parList; List<Map<String, String>> sonList=new ArrayList<>(); // 读取xml内容 parList = XmlUtil.getXmlComent(xmlPath); // 根据名字进行区分 for (int i=0;i< parList.size();i++) { Map map = (Map)parList.get(i); if (map.containsKey(methodName)) { Map<String,String> subMap = (Map<String,String>) map.get(methodName); sonList.add(subMap); } } if (sonList.size() > 0) { return sonList; }else{ Assert.assertTrue(sonList.size()!=0,parList+"为空,找不到属性值:"+methodName ); return null; } } public Object[][] mapsToArray(List<Map<String, String>> maps) { int singleListSize = maps.size(); // 创建一个二维数组 Object[][] testData = new Object[singleListSize][]; for (int singleSize = 0; singleSize < singleListSize; singleSize++) { Map<String, String> singleMap = maps.get(singleSize); testData[singleSize] = new Object[]{singleMap}; } // 返回数据传给脚本 return testData; } }
函数说明:
dataProviderSource:根据用例位置及sheet名字来读取excel中的内容
getXmlData : 根据现在运行的test名及xml所在位置来读取excel所在位置及sheet名字
mapsToArray : 将 map 转换 成 Array
创建LoginElement.java 并编写以下内容:
package medical.manual.handles; import java.lang.reflect.Method; import java.util.HashMap; import java.util.List; import java.util.Map; import org.testng.annotations.DataProvider; import medical.BusinessFile; public class LoginElement extends BusinessFile { // 用于存储元素路径及元素类型 private Map<String, String> loginElement; private void setPathAndType(String elePath, String pathType) { loginElement = new HashMap<>(); loginElement.put("elePath", elePath); loginElement.put("pathType", pathType); } public Map<String, String> getLoginTitle() { setPathAndType("h3.title", "css"); return loginElement; } public Map<String, String> getLoginUser() { setPathAndType("username", "name"); return loginElement; } public Map getLoginUserError() { setPathAndType("form > div:nth-child(2) > div > div.el-form-item__error", "css"); return loginElement; } public String getUserErrorMsg() { // 账号输入框错误提示语 return "请填写账号"; } public Map getLoginPass() { setPathAndType("password", "name"); return loginElement; } public Map getLoginPassError() { setPathAndType("div.el-form-item.el-tooltip.is-error.is-required > div > div.el-form-item__error", "css"); return loginElement; } public String getPassErrorMsg() { // 密码输入框错误提示语 return "请填写密码"; } public Map getLoginButton() { setPathAndType("form > button:nth-child(4)", "css"); return loginElement; } public Map getLoginRegister() { setPathAndType("form > button:nth-child(5)", "css"); return loginElement; } private Map getLoginError() { setPathAndType("body > div.el-message.el-message--error", "css"); return loginElement; } public Method getLoginPageElement(String methodName) { Method getPassErrorMsg = null; try { // 根据方法名获得指定的方法, 参数name为方法名,参数parameterTypes为方法的参数类型 getPassErrorMsg = LoginElement.class.getDeclaredMethod(methodName); } catch (NoSuchMethodException e) { e.printStackTrace(); } return getPassErrorMsg; } @DataProvider public Object[][] getLoginData(Method method) { String xmlpth = ".\\src\\main\\java\\medical\\manual\\user\\TestUserLogin.xml"; List<Map<String, String>> xmlData = getXmlData(method.getName(),xmlpth); String load = xmlData.get(0).get("load"); String sheetName =xmlData.get(0).get("sheetName"); Object[][] testData = dataProviderSource(load,sheetName); return testData; } }
函数说明:
get***并且返回Map类型的函数 : 定义元素路径及路径类型(有css、id、name 、xpath等)
getLoginPageElement : 放射机制获取元素路径
getLoginData : 数据驱动DataProvider中数据来源的准备
四: 用例操作类
创建LoginBusiness.java并编写如下内容
package medical.manual.business; import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; import java.util.Map; import org.openqa.selenium.By; import org.openqa.selenium.JavascriptExecutor; import org.openqa.selenium.WebDriver; import org.openqa.selenium.WebElement; import org.openqa.selenium.support.ui.ExpectedConditions; import org.openqa.selenium.support.ui.WebDriverWait; import org.testng.Assert; import toolskit.InformationLog; import toolskit.carrier.BrowserDriver; import toolskit.carrier.DriverFactory; import toolskit.exhibition.ExecuteFramework; import toolskit.exhibition.InterfaceShow; import toolskit.incomprehension.AbnormalCodeError; import toolskit.incomprehension.ResourceNotFoundException; import medical.manual.handles.LoginElement; import static toolskit.documents.ReadIni.readIni; public class LoginBusiness { public BrowserDriver browser; private InterfaceShow execute; private LoginElement loginElement; private WebDriver driver; public LoginBusiness(String filename) { Map<String, Object> url_ini = readIni(filename,""); String driverType =((Map<String, String>) url_ini.get("dz_login")).get("driver"); String webUrl = ((Map<String, String>) url_ini.get("dz_login")).get("url"); this.browser = DriverFactory.getDriverBrowser(driverType,webUrl); this.driver = browser.getDriver(); this.loginElement = new LoginElement(); this.execute = new ExecuteFramework(driver); } private String getElement(String elePath, String pathType) { String errorText = execute.getAttributeTextValue(elePath, pathType, null, "text"); return errorText; } private void inputUserInfo(String loginFunction, String userData) { try { Method getPassErrorMsg = loginElement.getLoginPageElement(loginFunction); Map loginMap = (Map) getPassErrorMsg.invoke(loginElement); String elePath = (String) loginMap.get("elePath"); String pathType = (String) loginMap.get("pathType"); InformationLog.inputLogInfo("the element: " + loginMap.get("elePath") + " input data " + loginMap.get("pathType")); WebElement username = execute.VisibleFocus(elePath, pathType); execute.HandleVisibleInput("", "", username, userData); // 利用js代码在指定的元素上失去焦点 JavascriptExecutor driver_js = ((JavascriptExecutor) driver); driver_js.executeScript("arguments[0].blur();", username); } catch (InvocationTargetException | IllegalAccessException e) { e.printStackTrace(); } } /** * 获取输入框中出现错误的提示语 * * @param loginFunction 提示语所在位置的指定函数 * @param loginErrorFun 提示语内容 */ private void getUserErrorInfo(String loginFunction, String loginErrorFun) { Method getPassErrorMsg; Map loginMap; String loginError; try { // 找到错误提示语位置 getPassErrorMsg = loginElement.getLoginPageElement(loginFunction); loginMap = (Map) getPassErrorMsg.invoke(loginElement); String elePath = (String) loginMap.get("elePath"); String pathType = (String) loginMap.get("pathType"); // 找到错误提示语 String errorText = getElement(elePath, pathType); // 获取内置提示语进行比较 getPassErrorMsg = loginElement.getLoginPageElement(loginErrorFun); loginError = (String) getPassErrorMsg.invoke(loginElement); if (errorText != null && errorText.equals(loginError)) { InformationLog.inputLogInfo(" element error message: " + errorText); } else { InformationLog.inputLogInfo(" element No error message: "); } } catch (Exception e) { e.printStackTrace(); } } private void clickLogin() { // 找到错误提示语位置 Method getPassErrorMsg = loginElement.getLoginPageElement("getLoginButton"); Map loginMap = null; try { loginMap = (Map) getPassErrorMsg.invoke(loginElement); } catch (Exception e) { e.printStackTrace(); } assert loginMap != null; String elePath = (String) loginMap.get("elePath"); String pathType = (String) loginMap.get("pathType"); WebElement userError = execute.VisibleFocus(elePath, pathType); if (userError != null) { userError.click(); } else { Assert.assertThrows(NullPointerException.class, () -> { throw new AbnormalCodeError("excel中出现不符合要求的资源:"); }); //failed } } public void medicalRecords(Map<?, ?> param) { // 输入内容 inputUserInfo("getLoginUser", (String) param.get("username")); inputUserInfo("getLoginPass", (String) param.get("password")); // 点击登录按钮 clickLogin(); // 判断错误是否出现 String errorType = (String) param.get("type"); if ("info".equals(errorType)) { getUserErrorInfo("getLoginUserError", "getUserErrorMsg"); getUserErrorInfo("getLoginPassError", "getPassErrorMsg"); } else if ("page".equals(errorType)) { WebElement userError = new WebDriverWait(driver, 5) .until(ExpectedConditions.visibilityOfElementLocated(By.cssSelector("body > div.el-message.el-message--error"))); String errorText = userError.getText(); InformationLog.inputLogInfo("page pupop error info: " + errorText); } else { //failed Assert.assertThrows(NullPointerException.class, () -> { throw new ResourceNotFoundException(); }); } } }
函数说明:
实例化LoginBusiness时需要传入ini所在位置,实例化时就创建浏览器对象、元素存储对象、元素操作对象
getElement : 元素text文字获取函数,这里统一调用也可以不进行创建。
inputUserInfo : 内容输入函数,其中loginFunction为LoginElement文件中对应的get***函数名,userData为需要输入的内容该内容需要从excel中读取
getUserErrorInfo : 内容输入错误时,提示语的获取,loginFunction为LoginElement文件中对应的get***函数名,loginErrorFun为出现的提示语,提示语也是从excel中读取
clickLogin : 执行元素点击操作
medicalRecords : 将上诉的函数结合在一起,整合成整个流程。流程为:账号密码号密码输入-->提示元素校验-->执行点击操作。
说明:
整体思路是:TestUserLogin 中test运行前实例化LoginBusiness,并由此打开浏览器及进入相应的url。
在运行test时由LoginElement中name为getLoginData的dataProvider来准备数据(准备过程中主要是通过xml读取用例位置)
最后将excel中的全部数据逐条进行返回最后来运行。