返回博客主页
← 所有文章

NativeScript Dev Appium 的最新功能?

2019 年 11 月 20 日 - 作者:Svetoslav Tsenov

如果您不熟悉这个插件,那么如果您认真考虑您的移动应用程序,您一定要尝试一下。NativeScript-dev-appium 是一个开源插件,它包装/提供对 Appium 的访问,它是测试 NativeScript 应用程序的一种合适方法。

nativescript-dev-appium 插件的主要优先事项是

  • 易用性
  • 跨平台
  • 与第三方产品和服务的兼容性

牢记这些,我们提供了一些新功能,可以让您在 NativeScript 中使用 Appium 的体验更加出色。

我们改进了什么?

让我们从您尝试在本地机器上运行测试时开始,这可能很痛苦。Appium 需要 一堆依赖项 需要安装,不仅如此,我们还需要提供功能,并可能还需要为我们使用的 JavaScript 测试框架进行一些额外的设置。所以,让我们诚实地说 - 解决依赖关系并不那么舒服,但至少大多数情况下这是一次性工作。不幸的是,我们这边也无能为力,所以我们专注于如何缓解测试的执行,尤其是在开发过程中。

测试执行

从那里开始,我们首先需要做的是消除提供 Appium 功能的必要性。所以,假设您想在您的应用程序已经进行实时同步的模拟器/仿真器上运行测试。以前,您被迫提供强制性的 Appium 功能,但现在您只需要指定平台即可

之前 npm run e2e -- --runType some-device-capabilities

现在 npm run e2e android/ios

就是这样!如果您有多个模拟器/仿真器在运行,会发生什么?'nativescript-dev-appium' 目前无法同时执行多个测试,但您可以提供额外的参数,例如 --device.name="android-emulator-28",测试将仅在指定设备上执行。

嗯,这看起来不错,但我们必须处理这样一个事实,即每次执行此命令时,Appium 都需要启动 appium-server,然后启动 appium-driver,这总是需要一些时间。所以,我们想出了一个想法,单独启动 Appium 进程,并重用已经存在的会话。得益于此,不再需要等待 Appium 初始化。为此,您需要在测试执行之前执行另一个命令。

首先,在单独的终端中运行:./node_modules/.bin/ns-appium [android 或 ios] --startSession,并等待 sessionId 显示出来。除非必要,否则不要关闭该终端。

然后,您可以像 npm run e2e -- --attachToDebug 那样简单地执行测试,或者缩写为 npm run e2e -- -a,或者简单地创建一个命令,例如 npm run e2e-debug

当然,如果有多个会话启动,我们需要提供 --sessionId。另一种选择是使用 Appium 桌面应用程序启动应用程序,并将其附加到 Appium 中提供的会话。请记住,如果您想测试一些操作/手势或找到本地化元素的最佳策略,这非常方便。

为了更好地说明这个想法,让我们看一下我在构建材料组件的一些新测试时如何进行调试

测试报告

与测试相关的另一个非常重要的事情是观察测试结果。从现在开始,您也可以使用 Mochawsome,它将显示图像比较的结果。请记住,如果您是第一次安装 nativescript-dev-appium,所有这些功能都将自动设置,您无需手动执行。在 setup.ts/js 中初始化报告上下文

const addContext = require('mochawesome/addContext');
const testReporterContext = <ITestReporter>{};
testReporterContext.name = "mochawesome";
testReporterContext.reportDir = "mochawesome-report";
testReporterContext.log = addContext;
testReporterContext.logImageTypes = [LogImageType.screenshots];
nsCapabilities.testReporter = testReporterContext;

每个 describe 应该包含一个 before 钩子,其中应该提供报告上下文

  describe("sample scenario", async function(){
      let driver: AppiumDriver;

      before("start server", async function () {
         nsCapabilities.testReporter.context = this;
         await startServer();
      });
    …
  });

设置 mocha 选项,使用 Mochawesome 报告程序的文件 [待办:哪个文件?]

--timeout 999999
--recursive e2e
--reporter mochawesome 
--reporter-options quiet=true,html=true,inline=true,autoOpen=true
--exit

图像比较

viewPortRect 选项,换句话说,应该将显示的哪个部分包含在图像比较中。幸运的是,Appium 提供了 viewPortRect 功能,帮助我们了解应该将显示的哪个部分包含在图像比较中。此功能自 Appium >= 1.10.0 与 UIAutomator2(Android) 和 XCUITests(iOS) 结合使用以来一直可用。如果您需要覆盖此设置,可以在您的 appium 功能文件中提供 viewPortRect。但不止这些。您还可以为每个测试提供不同的矩形,ns-dev-appium 将在图像验证中考虑该矩形。

driver.imageHelper.options.cropRectangle = {x:150, y:150, width: 150, height: 150}

我们还提供了一些额外的 方法,可以帮助多次比较图像并在测试结束时断言结果。假设您的测试中有多个操作,并且需要在每个操作之后比较图像。

   beforeEach(async function () {
      // this property will be used to set image name in case it is omitted in test
       driver.imageHelper.testName = this.currentTest.title;
   });

   it(`sample-test`, async function () {
      const button = await driver.waitForElement(`sampleBtn`);  
       await button.click();
       // This method will create image (if not exists) with the name as the test name.
       // In this case, the image name will be `sample-test.png`
       await driver.imageHelper.compareScreen();

        await button.click();
        // This method will create an image (if not exists) with the same name as the test                           // and will add a cpunter as a postfix. In this case, the image name will be `sample-test-2.png`  
       await driver.imageHelper.compareScreen();

      // assert the results of image comparisson.
       assert.isTrue(driver.imageHelper.hasImageComparisonPassed());
   });

每个 comare 方法也接受 IImageCompareOptions,它可以用来覆盖图像比较中使用的默认属性。

export interface IImageCompareOptions {
   imageName?: string;
   timeOutSeconds?: number;

   /**
    * pixel
    * percentage thresholds: 1 = 100%, 0.2 = 20%"
    */
   tolerance?: number;

   /**
    * pixel
    * percentage thresholds: 1 = 100%, 0.2 = 20%"
   */
   toleranceType?: ImageOptions;

   /**
    * Wait milliseconds before capture creating image
    * Default value is 2000
    */
   waitBeforeCreatingInitialImageCapture?: number;

   /**
    * This property will preserve not to add be added _actual postfix on initial image capture
    */
   donNotAppendActualSuffixOnIntialImageCapture?: boolean;

   /**
    * This property will ensure that the image name will not be manipulated with count postfix.
    * This is very convenient in order to reuses image.
    * Default value is false.
    */
   keepOriginalImageName?: boolean;

   /**
    * Clip image before compare. Default value excludes status bar(both android and ios) and software buttons(android).
    */
   cropRectangle?: IRectangle;

   /**
    * Default value is set to true which means that nativescript-dev-appium will save the image
    * in original size and compare only the part which cropRectangle specifies.
    * If false, the image size will be reduced and saved by the dimensions of cropRectangle.
    */
   keepOriginalImageSize?: boolean;


   /**
    * Default value is set to false. nativescript-dev-appium will recalculate view port for iOS
    * so that the top/y will start from the end of the status bar
    * So far appium calculates it even more and some part of safe areas are missed
    */
   keepAppiumViewportRect?: boolean;

   /**
    * Defines if an image is device-specific or only by the platform.
    * Default value is true and the image will be saved in device-specific directory.
    * If the value is set to false, the image will be saved under ios or android folder.
    */
   isDeviceSpecific?: boolean;

   /**
    * Overwrite actual image if doesn't match. Default value is false.
    */
   overwriteActualImage?: boolean;
}

搜索方法

waitForElement - 此方法尝试通过自动化文本查找元素。

CI

让我们来谈谈下一个合乎逻辑的步骤:“自动化应用程序的测试”。这个主题非常广泛,但我将尝试涵盖主要要点,这些要点对于 CI 尤其重要。ns-dev-appium 应该能够在 Appium 支持的所有平台或服务上工作。通常,对于本地运行,ns-dev-appium 依赖于 mobile-devices-controller,但此插件并非旨在与不同的供应商合作。这就是为什么在这些运行中应该应用“--ignoreMobileController”。对于 SauceLab,有一个额外的选项 --sauceLab 可以提供 SauceLab 所需的一些额外设置,并且还会自动忽略 mobile-devices-controller 插件。已经有 一些博客文章 解释了如何在 SauceLabs 和其他平台上执行测试,所以我不会深入研究这个方向。我将尝试关注可能对您有用的其他选项。

--imagesPath - 相对于 resources/images 的图像路径。由于模拟器名称对于所有 API 级别都是相同的,因此您需要在存储特定于设备的图像时对其进行区分。

"isHeadless": true - 使用无头模式。此设置应在 appium 功能中提供

    "android28": {
        "platformName": "Android",
        "platformVersion": "28",
        "deviceName": "Emulator-Api28-Google",
        "avd": "Emulator-Api28-Google",
        "lt": 60000,
        "newCommandTimeout": 720,
        "isHeadless": true,
        "noReset": false,
        "fullReset": false
    },

下一步是什么?

我们的下一个目标之一是启用在多个设备上同时执行测试。这将帮助您扩展您的测试基础设施,并减少等待时间,从而提高工作效率。

但 Appium 集成的路线图主要由您决定。如果您有任何功能请求,或者只是遇到了您不知道如何解决的问题,请在 nativescript-dev-appium 存储库 中创建一个新问题。