我们使用Page Object模式自动执行Android应用程序的UI测试

图片

Page Object模式出现在Web测试中,并证明在那里非常好。 当我开始自动执行android应用程序的测试时,我想到的第一件事。 我在网络上寻找信息,问我的同事,原则上没有找到不尝试的原因。 我建议看看结果如何。

经典的Page Object包含两个抽象级别:页面元素和测试。 我再强调一个-业务逻辑。 我注意到,构建框架的方式将极大地影响将来编写测试的难易程度及其支持。 我试图使测试代码看起来像是由普通测试人员编写的普通测试用例。 即 我从头开始:

  1. 我正在编写漂亮清晰的测试用例代码,
  2. 我在业务逻辑层中通过测试用例实现方法,
  3. 我描述了测试所需的元素。

这种方法很好,因为我们不需要做任何额外的工作-该框架是根据测试正常工作所必需的。 可以说,这就是MVP在测试中的概念:他们很快做出了贡献,并且已经开始带来好处。 如果您首先写了数千行,描述了应用程序的页面以及如何与它们交互,并且三个月后您第一次单击就陷入了“漏洞”,并且意识到必须以不同的方式做所有事情,那么大部分创建工作将永远注定“在git的地下室中收集灰尘...真正的测试人员知道,发现错误的越早,修复它的成本就越低。 在所有事物中都使用这种方法-在几个小时内编写了一个测试,尝试了,不喜欢-扔掉了,吸取了教训,继续前进。

所以输入是:

  • Android应用程序,用于在证券交易所进行交易;
  • Java与开发人员在同一堆栈中工作;
  • 基本框架UI Automator;
  • 您需要在应用程序中编写登录测试。

项目准备


由于我尝试将尽可能多的集成到开发过程中,所以我没有开始创建新项目。 根据文档 ,仪器测试必须放置在src/androidTest/java文件夹中。 在我的情况下,收集器已经配置好了,如果有什么问题,请阅读构建配置 。 我们还需要开发环境,Android SDK,仿真器,工具,平台工具和仿真器所需的平台。 如果您使用的是Android Studio,则可以通过SDK Manager快速安装所有这些工具:



测试层


正如我在上面所写,我们将在应用程序中自动执行登录测试。 请记住,代码应看起来像常规测试用例:

前提条件:运行应用程序。
步骤1:使用myLogin / myPassword帐户登录。
步骤2:检查当前用户的名称。
预期结果:当前用户是Ivan Ivanov。

小免责声明:根据设计测试的最佳实践,在您需要创建/找到帐户的前提下。 为了简化示例,我省略了这一刻。

我们的课程如下所示:

 @RunWith(AndroidJUnit4.class) public class LoginTests { private TestApplication myApp; @Before public void setUp() { myApp = new TestApplication(); } @Test public void testLogin() { myApp.login("myLogin","myPassword"); String currentUser = myApp.getCurrentUserName(); assertEquals("Wrong name", " ", currentUser); } @After public void tearDown() { myApp.close(); } } 

业务逻辑


该测试使用TestApplication()类及其两个方法: login()getCurrentUserName() 。 另外,您需要一个类构造函数(在其中启动应用程序)和close()方法。

 public class TestApplication { private UiDevice device; private PageObject page; public TestApplication() { } public void login(String login, String password) { } public String getCurrentUserName() { return "" } public void close() { } } 

我们的类的实例将具有两个变量:

  • device ,属于android.support.test.uiautomator.UiDevice类-通过它我们与设备进行交互;
  • pagePageObject类,我们将在下一节中创建。

让我们从构造函数开始。 在其中,创建变量实例并运行应用程序:

 public TestApplication() { // Connect to device device = UiDevice.getInstance(InstrumentationRegistry.getInstrumentation()); device.pressHome(); // Get launch intent String packageName = InstrumentationRegistry.getTargetContext() .getPackageName(); Context context = InstrumentationRegistry.getContext(); Intent intent = context.getPackageManager() .getLaunchIntentForPackage(packageName) .addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK); // Stat application context.startActivity(intent); // Get page objects page = new PageObject(device, packageName); } 

启动应用程序的一些技巧
为了更好地控制被测应用程序,可以增加启动器(如果您“冷”运行仿真器)和应用程序本身启动的期望。 文档中也建议这样做。

注意:仅当您的测试与应用程序本身在同一项目中时,才适合通过android.content.Context.getTargetContext()运行应用程序。 如果单独使用,则有必要浏览菜单。

测试的业务逻辑是用户必须采取的特定步骤,以获得任何有意义的(对用户而言)结果。 在您自己的超声下登录是一个重要的结果。 步骤:单击“登录”按钮,在“登录”字段中输入用户名,在“密码”字段中输入密码,然后单击“登录”按钮。 因此,我们的方法包含以下步骤:

 public void login(String login, String password) { page.login().click(); page.loginEntry().setText(login); page.passwordEntry().setText(password); page.signIn().click(); } 

要获取当前用户,一切都变得更加简单,只需获取字段值即可:

 public String getCurrentUserName() { return page.currentUserName().getText(); } } 

要关闭该应用程序,只需单击“主页”按钮:

 public void close() { device.pressHome(); } 

页面元素的描述


该层的概念是它应该返回准备就绪的元素(在我们的上下文中,这是类android.support.test.uiautomator.UiObject2 )。 也就是说,消费者不必担心对象的状态,如果他返回了对象,则可以立即与他进行交互:单击,填写或阅读文本。 这是一个重要的结果-在这一层中,我们将实现期望:

 private UiObject2 getUiObject(BySelector selector) { return device.wait(Until.findObject(selector), 10000); } 

上面定义的方法将由我们的PageObject类的公共接口使用。 登录字段示例:

 public UiObject2 loginEntry() { return getUiObject(loginEntrySelector()); } 

剩下要确定的选择器,我们将通过该选择器找到该字段。 使用android.support.test.uiautomator.By类的静态方法android.support.test.uiautomator.BySelector最方便地获取android.support.test.uiautomator.BySelector的实例。 我同意这样的发展,在任何地方,只要有可能,都会有唯一的资源ID:

 private BySelector loginEntrySelector() { return By.res(packageName, "login"); } 

在工具包(安装在“准备”部分中)中的uiautomatorviewer实用程序中检查界面很方便:



选择所需的元素,然后在“节点详细信息”部分中查看资源ID。 它由程序包的名称以及实际上的标识符组成。 我们在TestApplication类的构造函数中获得了包的名称,并在创建PageObject时使用了它。

完整代码:

PageObject类
 public class PageObject { private UiDevice device; private final String packageName; private BySelector loginButtonSelector() { return By.res(packageName, "user_view"); } private BySelector loginEntrySelector() { return By.res(packageName, "login"); } private BySelector passwordEntrySelector() { return By.res(packageName, "password"); } private BySelector signInSelector() { return By.res(packageName, "btnLogin"); } private BySelector userNameSelector() { return By.res(packageName, "user_name"); } public PageObject(UiDevice device, String packageName) { this.device = device; this.packageName = packageName; } public UiObject2 login() { return getUiObject(loginButtonSelector()); } public UiObject2 loginEntry() { return getUiObject(loginEntrySelector()); } public UiObject2 passwordEntry() { return getUiObject(passwordEntrySelector()); } public UiObject2 signIn() { return getUiObject(signInSelector()); } public UiObject2 currentUserName() { return getUiObject(userNameSelector()); } private UiObject2 getUiObject(BySelector selector) { return device.wait(Until.findObject(selector), 10000); } } 


运行测试


仅此而已,它仍然可以运行。 首先,连接到设备或启动仿真器。 使用adb devices命令检查连接(adb实用程序是platform-tools的一部分):

 List of devices attached emulator-5554 device 

如果有问题,那就做

 gradlew.bat connectedAndroidTest 

并享受“注入的机器人,而不是人类”的方式(c)。

Source: https://habr.com/ru/post/zh-CN416397/


All Articles