
Page Object模式出现在Web测试中,并证明在那里非常好。 当我开始自动执行android应用程序的测试时,我想到的第一件事。 我在网络上寻找信息,问我的同事,原则上没有找到不尝试的原因。 我建议看看结果如何。
经典的Page Object包含两个抽象级别:页面元素和测试。 我再强调一个-业务逻辑。 我注意到,构建框架的方式将极大地影响将来编写测试的难易程度及其支持。 我试图使测试代码看起来像是由普通测试人员编写的普通测试用例。 即 我从头开始:
- 我正在编写漂亮清晰的测试用例代码,
- 我在业务逻辑层中通过测试用例实现方法,
- 我描述了测试所需的元素。
这种方法很好,因为我们不需要做任何额外的工作-该框架是根据测试正常工作所必需的。 可以说,这就是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
类-通过它我们与设备进行交互;page
, PageObject
类,我们将在下一节中创建。
让我们从构造函数开始。 在其中,创建变量实例并运行应用程序:
public TestApplication() {
启动应用程序的一些技巧为了更好地控制被测应用程序,可以增加启动器(如果您“冷”运行仿真器)和应用程序本身启动的期望。
文档中也建议这样做。
注意:仅当您的测试与应用程序本身在同一项目中时,才适合通过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)。