使用多个同时Appium会话测试实时用户交互

​​​​​

我们使用和需要测试的许多应用程序都涉及多个用户的实时交互,这些用户坐在自己的设备或浏览器前。“标准”Appium测试涉及一个驱动程序对象,代表一个Appium会话,自动化单个设备。我们如何扩展Appium的使用,使我们能够协调多个设备,就像多个用户自发地协调他们自己的行为一样?

多用户交互示例

首先,让我们来看看多用户或多设备测试的一些常见用例:

  1. 涉及一个或多个用户进行真实的实时交互的聊天应用
  2. 一个拼车应用程序,涉及两个当事人--骑手,谁要求乘坐使用一个应用程序,和司机,谁可以接受和拿起使用同一个应用程序的骑手。骑手和司机保持不断的互动,通过更新地图,显示他们的位置。
  3. 一个食品配送应用程序,涉及三方--请求食物的人,准备食物的餐厅,以及从餐厅取食物并将其送到请求者的送货人。

当然,许多其他应用程序涉及不一定实时的用户交互。例如,任何社交应用程序都可以让用户喜欢或评论其他用户的帖子。在正常情况下,可以将其设想为异步发生,而不是在真实的时间内发生。但是,许多相同的应用程序也希望能够测试UI是否在真实的时间更新,当另一个用户与某些内容交互时。例如,当我使用Twitter时,如果有人喜欢或转发我的帖子,我会收到应用内通知(而不是系统通知)。测试这个特殊的特性需要我们在这里讨论的相同类型的多用户交互。

多设备流的背景

我想在本指南中传达的基本观点是,Appium不需要特殊的帮助来适应多设备,多用户,实时测试场景。这是真的,因为关于Appium的以下事实(你可能已经知道了):

  1. Appium会话由测试代码中的对象表示。没有什么可以阻止你拥有多个这样的对象。
  2. Appium服务器可以处理多个同时进行的会话(通过适当的配置以确保会话不会互相干扰)。

这两个事实使得实现实时多设备流在技术上是微不足道的(如果从测试开发的角度来看并不总是直观的话)。现在,在上面的第2个问题上有一个小警告--因为Appium会话利用某些系统资源(主要是TCP端口)与特定设备通信,如果你想在一台机器上同时运行多个Appium会话,你需要包括一些功能,指导Appium为每个会话使用特定的端口。这些信息已经在Appium Pro关于并行运行多个Appium测试的文章中介绍过了。从Appium的角度来看,在不同设备上并行运行的相同测试之间没有区别,或者一个测试包含多个设备来测试用户交互流。

我们的多用户AUT

为了展示Appium的多设备测试,我开发了一个简单的聊天应用程序,名为Appium Pro Chat。这是一个非持久性的多通道聊天室,没有内存,没有数据存储,也没有(我犹豫着要不要加上)安全性。欢迎在浏览器中试用!你可以打开两个浏览器或标签,选择一个用户名,并加入同一个频道,看看它的行动。我将实现的基本测试是这样的:

  1. 用户1选择用户名并加入频道
  2. 用户2选择一个用户名并加入与用户1相同的频道
  3. 用户1和用户2都在聊天中输入内容
  4. 断言最终的聊天记录以正确的顺序包含他们的消息

这是一个简单的测试,但必须涉及多个Appium设备和多个Appium会话的协调。

多设备设置

在这个例子中,我将为用户1使用iOS模拟器,为用户2使用Android设备(Galaxy S7)。我需要做的第一件事是确保可以在其中的每一个上启动Appium会话,因此我为每个创建了一个帮助器方法,该方法仅返回适当的驱动程序实例。

private IOSDriver<WebElement> getSafari() throws MalformedURLException {
    DesiredCapabilities capabilities = new DesiredCapabilities();
    capabilities.setCapability("platformName", "iOS");
    capabilities.setCapability("platformVersion", "13.3");
    capabilities.setCapability("deviceName", "iPhone 11");
    capabilities.setCapability("browserName", "Safari");
    capabilities.setCapability("automationName", "XCUITest");
    return new IOSDriver<>(new URL("http://localhost:4723/wd/hub"), capabilities);
}

private AndroidDriver<WebElement> getChrome() throws MalformedURLException {
    DesiredCapabilities capabilities = new DesiredCapabilities();
    capabilities.setCapability("platformName", "Android");
    capabilities.setCapability("deviceName", "Android Emulator");
    capabilities.setCapability("browserName", "Chrome");
    capabilities.setCapability("automationName", "UiAutomator2");
    return new AndroidDriver<>(new URL("http://localhost:4723/wd/hub"), capabilities);
}

现在,在我的测试setUp方法中,我确保实例化两个驱动程序,它们存储为我的类中的字段,例如(省略该类的其他功能):

public class Edition118_Multi_Device {
    private IOSDriver<WebElement> safari;
    private AndroidDriver<WebElement> chrome;

    @Before
    public void setUp() throws MalformedURLException {
        safari = getSafari();
        chrome = getChrome();
    }

    @After
    public void tearDown() {
        if (safari != null) {
            safari.quit();
        }
        if (chrome != null) {
            chrome.quit();
        }
    }
}

你可以看到,没有什么特别的让多个会话同时进行-我只是首先在iOS上的Safari上创建会话,然后在Android上的Chrome上创建会话。安装和拆卸现在处理两个驱动程序,而不是一个。在这个例子中,我串行地实例化这些会话;如果我想进一步优化,我可以在单独的线程中同时实例化它们,但是这增加了不必要的复杂性。

在单个测试中协调多个驱动程序

现在,我们需要使用这两个驱动程序(safarichrome对象),使它们在一个测试过程中以真实的时间彼此交互。在展示测试方法之前,我先解释一下这个计划:两个用户都将交换兰斯顿休斯(Hughes)的诗歌《哈莱姆》(Harlem)中的诗句。为了封装将用于支持测试的数据,我们将在类的顶部添加一组字段:

private static final String CHAT_URL = "https://chat.appiumpro.com";
private static final String CHANNEL = "Harlem";
private static final String USER1_NAME = "Langston";
private static final String USER2_NAME = "Hughes";
private static final ImmutableList<String> USER1_CHATS = ImmutableList.of(
        "What happens to a dream deferred?",
        "Or fester like a sore---and then run?",
        "Or crust and sugar over---like a syrupy sweet?",
        "Or does it explode?");
private static final ImmutableList<String> USER2_CHATS = ImmutableList.of(
        "Does it dry up like a raisin in the sun?",
        "Does it stink like rotten meat?",
        "Maybe it just sags like a heavy load.",
        "........yes");

(Note我有,也许是不礼貌的,但我相信与诗的精神一致,添加了我自己的最后一行,部分是为了使用户2的消息列表等于用户1的长度)。通过在ImmutableLists中设置的数据,我们能够以一种非常简洁的方式重新定义聊天并实现用户交互。

接下来,我想创建一组帮助器方法,以便在两个用户之间重用功能。两个用户都必须登录并加入一个频道,两个用户都必须发送消息。同样,我们可以从任何一个用户的角度阅读聊天记录。因此,我们可以将所有这些因素分解为适当的helper方法:

private void joinChannel(RemoteWebDriver driver, String username, String channel) throws MalformedURLException {
    WebDriverWait wait = new WebDriverWait(driver, 10);
    driver.navigate().to(new URL(CHAT_URL));
    wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#channel"))).sendKeys(channel);
    driver.findElement(By.cssSelector("#username")).sendKeys(username);
    driver.findElement(By.cssSelector("#joinChannel")).click();
}

private void sendChat(RemoteWebDriver driver, String message) {
    WebDriverWait wait = new WebDriverWait(driver, 10);
    wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#sendMessageInput"))).sendKeys(message);
    driver.findElement(By.cssSelector("#sendMessageBtn")).click();
}

private String getChatLog(RemoteWebDriver driver) {
    WebDriverWait wait = new WebDriverWait(driver, 10);
    return wait.until(ExpectedConditions.presenceOfElementLocated(By.cssSelector("#messages"))).getText();
}

请注意,每个类都有一个RemoteWebDriver对象,因为它是IOSDriverAndroidDriver的适当超类。我们不知道在这些方法中,我们是在自动化iOS Safari还是Android Chrome,这是一件好事。它使代码通用。

现在,我们可以编写测试本身:

@Test
public void testChatApp() throws MalformedURLException {
    joinChannel(safari, USER1_NAME, CHANNEL);
    joinChannel(chrome, USER2_NAME, CHANNEL);
    for (int i = 0; i < USER1_CHATS.size(); i++) {
        sendChat(safari, USER1_CHATS.get(i));
        sendChat(chrome, USER2_CHATS.get(i));
    }
    System.out.println(getChatLog(chrome));
    try { Thread.sleep(4000); } catch (Exception ign) {}
}

如你所见,它相当紧凑。我们让每个客户端加入同一个频道,然后浏览他们各自的聊天消息列表,将每个消息发送到频道。最后,我从其中一个用户那里获取聊天记录,并将其打印到控制台。当然,在实际测试中,我们可以对消息框的内容进行断言,甚至断言每个用户看到的聊天记录之间的相似性。最后,为了在运行测试时产生视觉效果,我们等待4秒才关闭所有内容(同样,实际测试中不会出现这种情况)。

Recap

这是真的有它!让我强调一下我们在这里采取的策略,这种策略可以适用于任何多用户流:

  1. 定义测试所需的用户数。
  2. 在设置中,为每个参与用户实例化一个Appium驱动程序对象,注意遵守并行运行Appium会话的所有规则。
  3. 在测试本身中,按照实际用户流的逻辑,交错使用单独驱动程序的命令(通常这些命令是连续发生的,因为一个用户的行为取决于另一个用户的行为,但如果可能和适当,命令可以在不同线程中同时运行)。
  4. 在拆卸,确保清理所有的驱动程序。

想看看这个多用户流的完整代码示例吗?在GitHub上查看!无论如何,让我知道你是否用Appium实现了任何有趣的多用户或多设备流。

Appium Pro通讯和网站是由Jonathan Lipps用爱制作的。

Appium是OpenJS基金会的注册商标。

© 2018 - 2024 HeadSpin. All rights reserved.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值