首页 > 编程知识 正文

appium自动化测试框架,appium自动化测试完整项目

时间:2023-05-05 06:29:23 阅读:26082 作者:862

自动化测试是研发人员进行质量保证的重要环节之一,良好的自动化测试机制可以使研发人员尽早发现编码中的逻辑缺陷,并前置风险。 在日常研发中,为了快速迭代,需要在各业务线上进行主流程的回归测试。 目前,这类测试大部分是人工进行的,耗时费力,重复劳动较多。 UI自动化测试与主流程回归相结合,既能保证代码质量,又能大大节约人力成本,可谓一举两得。

为什么需要UI自动化测试

原因主要有以下三点。 保证质量——,尽早发现代码缺陷,风险先行。

减少重复劳动、节约人力的——快速迭代需要经常进行主流程回归,并对整个主流程进行测试,需要相当大的人力成本。

统一标准——人对测试案例及业务的理解程度不同,标准可能存在不一致。

选择进行UI自动化测试时面临的问题工具。

减少对后端的依赖,避免测试环境后端不稳定导致的测试失败。

整合测试用例,增加重用,降低用例维护成本。

自动化测试工具比较

UI测试工具发展迅速,目前有Robotium、Appium、Espresso、UIAutomator、Calabash等,其中在Android中使用最广泛的是UIAutomator、Robotium

以下列表的比较说明:

uiautomator robot ium

(|(|(|) ) )

支持平台,安卓,H5

脚本语言

是否支持无源测试

支持API级别

除了Android、Hybrid类型的App外,Appium还可以在iOS设备上运行。 在以前的小组内同事进行过Appium方面的共享,在这方面有一定的基础,所以最终我们选择了Appium。

接口稳定性和数据可变性

根据业务特性,case在运行时经常向后端请求数据,并根据后端接口返回的数据来确定页面元素的显示。 因此,必须克服后端接口稳定性这两个难点

测试环境与在线不同,稳定在7x24内。 业务接口经常因依赖的外部环境异常而导致请求失败。 以前我们处理这种情况,但我们能做的事情往往有限,最糟糕的是,我们无法在第三方修复完成之前继续测试。 因此,如何稳定接口成为UI自动化测试必须面对的问题。

测试数据配置和存储

在克服1中提到的接口稳定难点后,仍然要面对第二难点——频繁修改配置以适应测试用例的条件。 举个例子,闪惠业务的情况是,对在用例中商户配置的很多情况进行测试。 (无优惠、未开始优惠、只有闪惠的优惠、与闪惠团购、闪惠折扣、闪惠赠品等)其中的条件复杂多样。 每次进行测试时,如果运行测试者在商户后台登录后手动更改配置,将花费大量的人力资源。 因此,需要找到一种使这种复杂的配置过程自动化的方法。

访问Appmock注意事项:要使用Appmock,App的基础网络请求模块必须基于能够切换mock地址的功能。

Appmock是美团平台集团打造的非常优秀的mock工具,其前身是美团同事舒适凉面撰写的wendong.dp。 Appmock允许浏览网络请求和mock。 那么,是否可以在运行自动测试用例时访问Appmock以获取预配置的mock数据? 做过相关APP研发的同事都知道,在APP这很容易做到。 只要访问某个特定的HTTP链接进行注册就可以了。

Appmock使用界面

这在Appmock的帮助下解决了“后端接口稳定性”问题。 如果将后端数据直接部署到Appmock,则请求失败的概率很小。 尽管如此,面对频繁修改配置的需求,不过是将修改操作从商家的后台页面转移到了mock系统。 有没有自动化修改配置的操作的方法?

在研究了Appmock的源代码后,我觉得我们可以自己构建mock-server,将不同阶段的mock数据存储在数据库中,并打开用于切换各个测试用例所需mock数据的网络接口具体的系统结构如下图所示。

上图显示了执行主用例的简单过程,需要在数据库中预先准备测试数据。 mock-server基于Appmock使用NodeJS完成二次开发。

制作测试用例

为了简化用例的创建并减少开发和维护的麻烦,请使用页面对象模式进行用例开发。

Page Object被定义为抽象页面的对象,通过封装页面功能来执行适当的操作。 其优点是减少重复代码,提高重用性。

提高代码的可读性、稳定性。

容易维护。

创建UI自动化测试框架的方法类似于MVC体系结构。 独立创建测试用例中的业务逻辑、每页之间的元素和测试数据。 以下都是队列业务主流程中的示例:

测试类配置

测试类

的组成包括setUp(),tearDown()方法以及各个测试用例testXXXX(),所有的测试用例必须以小写test开头,如正常排号下的testQueueNormalQueue():@Before

public void setUp() throws Exception {

File apk = new File(APK_NOVA);

DesiredCapabilities capabilities = DesiredCapabilities.android();

capabilities.setCapability("device", Platform.ANDROID);

capabilities.setCapability(CapabilityType.VERSION, "5.1");

…… // capabilities各个常量字段

driver = new AndroidDriver(new URL("http://127.0.0.1:4723/wd/hub"), capabilities);

splashScreen = new SplashScreen(driver);

mainPage = new MainPage(driver);

…… // Page Object初始化

}

@After

public void tearDown() throws Exception {

driver.quit();

}

@Test

public void testQueueNormalQueue() {

// 略

}

测试用例中不用直接对页面元素进行操作,我们所要做的事情仅仅是业务层面的逻辑,包括表单数据的提交、页面按钮的点击跳转等等。

页面类编写

页面类的编写采用Page Object模式,包括页面中会使用到的元素、页面元素的操作方法集以及页面元素的检验方法集。

所有的Page子类均继承BasePage父类,它要做的事情很简单,无非就是1个driver,2个driverWait用于延时加载的等待时间,以及页面元素的初始化:public class BasePage {

private static final int TIMEOUT = 1; // short timeout for web-element

private static final int TIMEOUT_LONG = 10; // long timeout for web-element

public AndroidDriver driver;

public WebDriverWait driverWait;

public WebDriverWait driverLongWait;

public BasePage(AndroidDriver driver) {

this.driver = driver;

this.driverWait = new WebDriverWait(this.driver, TIMEOUT);

this.driverLongWait = new WebDriverWait(this.driver, TIMEOUT_LONG);

PageFactory.initElements(this.driver, this); // 这句非常重要,如果不写的话尽管编译不会报错,但是后面要说的页面元素在运行时一个都找不到

}

}

然后是各个Page子类的实现方法:public class ShopInfoPage extends BasePage {

public ShopInfoPage(AndroidDriver driver) {

super(driver);

}

…… // 页面元素 @FindBy

…… // 操作方法,比如login()、clickXXXXXXButton()、gotoXXXXXXPage()

…… // 检验方法,比如checkLoaded()、checkLoginSuccess()、checkQueue_LoginReadyQueue()

}

Page子类的元素定位我们使用@FindBy注解方式进行统一的管理。

元素定位最基本的方法就是使用id/name/class等,如果不行的话就用相对复杂却无所不能的xpath,如:// 点击登录按钮

@FindBy(id = "login_tip")

private WebElement clickLoginButton;

// MAPI域名输入框

@FindBy(xpath = "//*[contains(@resource-id, 'id/mapi_item')]//*[contains(@resource-id, 'id/debug_domain')]")

private WebElement mapiDomainText;

Page中的操作和检验方法调用已经封装好的BaseUtils中的方法,如:BaseUtils.waitForElement(driverWait, loginButton).click(); // 等待元素出现并点击

Assert.assertTrue(BaseUtils.waitForElementVisibility(driverLongWait, usernameText)); // 检验元素应该展示在页面上

BaseUtils方法

BaseUtils中封装好了一些通用的方法,还需要不断完善并扩展。下面介绍其中一些常用及重要的方法:openDebugPanel():每次直接调用该方法来打开Debug面板,由于Debug面板是一个系统层面的悬浮窗,它不属于任何页面中的元素(你完全没办法通过ID甚至XPath获得)。

clickPoint():点击某个坐标+持续时间,坐标采用相对屏幕位移的方式(左上为0,0),这里只实现了简单的单指的点击操作,实际上driver.tap可以模拟多指的共同操作。

swipeToUp() & swipeToDown():上拉 & 下拉页面操作,需要传的是次数和每次持续时间,模拟手指在屏幕上的滑屏操作,主要用于刷新页面以及绕过某些有坑的scrollTo。

prepareMockData():这里要做的就是,在关键步骤操作前传入mock_data_id,我们会将数据请求发送给服务器,然后服务器从数据库拉到对应的mock data并更新。

saveScreenshot():ysdlt,截图。在每个重要的页面操作方法中加入即可,需要传入的是case_id以及操作或检查时的keyword,方便在用例执行完以后看截图分析和Bug复现。

waitForElementXXX():在预设等待时间内等待元素出现并定位元素。

UI自动化测试运行效果

在排队与闪惠两条业务线进行了UI自动化测试实践,它们执行完成全套用例的耗时均不超过20min。相比于之前人工进行主流程测试动辄花费半天的工作量的情况,大大降低了人力成本,将工程师宝贵的时间节约给了更有价值的研发工作。

当然,自动化测试前期的环境搭建、数据准备、用例编写等任务是必不可少的,这些准备工作很多都是一次性投入,一劳永逸,也正是自动化测试的价值所在。

参考资料

版权声明:该文观点仅代表作者本人。处理文章:请发送邮件至 三1五14八八95#扣扣.com 举报,一经查实,本站将立刻删除。