Detox实现ReactNative E2E自动化测试

 

Detox 是什么?

在创建新功能或修复错误后,我们通常会在我们的设备上安装该应用并手动测试。但是,当我们想要在标记版本之前验证所有新旧功能时,此过程可能会很麻烦。解放双手,是我们梦寐以求的。

Detox,一个用于测试 React Native 应用程序 Selenium 界面的端到端自动化测试工具。

Detox 是为移动端APP打造的灰盒端到端自动化测试框架。在 ReactNative 开发中,使用 js 测试框架 jest 或 mocha 来执行相应的测试脚本。通过对RN程序包中 package.json 增加 Detox 相关配置,并在RN程序包中增加测试案例文件夹 e2e(在其中增加测试案例)实现测试用例的编写和执行。

Detox 专注于同步(我们稍后会看到一个例子)例如添加 sleep(2000)等待后端完成请求,往往会在较慢的CI机器或网络上中断。使用Detox,以及谷歌开发的东西(适用于iOS的EarlGrey和适用于Android的Espresso),不仅可以自动等待完成请求,还可以等待动画,定时器等。

关于 Detox 更多的了解,大家可以看官方文档:Detox

同样分享一篇老外的分享:E2E Testing React Native with Detox + Screenshots

Detox 环境安装

Detox 的运行需要依赖以下插件环境

全局安装

1. Node.js (8.3.0 or higher)

brew update && brew install node

2. applesimutils

用于Apple模拟器的utils集合,Detox使用它与模拟器进行通信。

brew tap wix/brew
brew install applesimutils 

3. detox-cli 

Detox 命令行工具

npm install -g detox-cli

切到项目安装

4. detox 

npm install detox --save-dev

5. 在 package.json 中添加 detox 配置 

"detox": {
  "configurations": {
    "ios.sim.debug": {
      "binaryPath": "ios/build/Build/Products/Debug-iphonesimulator/example.app",
      "build": "xcodebuild -project ios/example.xcodeproj -scheme example -configuration Debug -sdk iphonesimulator -derivedDataPath ios/build",
      "type": "ios.simulator",
      "name": "iPhone 7"
    }
  }

6.  detox  支持 jest、mocha 编写测试用例

Jest

npm install jest --save-dev

Mocha

npm install mocha --save-dev 

Detox与Mocha和Jest没有紧密耦合,也没有与这个特定的目录结构紧密耦合。 两者都只是一个建议,很容易更换,而不涉及Detox本身的内部实现。

7. detox-cli 具有 detox init 初始化便捷命令,可自动完成第一次测试的设置。 根据第6步选择的测试运行器,运行以下命令之一 

 Jest

detox init -r jest

Mocha

detox init -r mocha

以上步骤执行完成后,detox 已成功配置到项目中。

文件结构分析

当执行了 detox init 命令后,detox-cli 会自动在项目根目录生成一个 e2e 文件夹,以 jest 为例,结构如下:

测试用例的代码我们会在firstTest.spec.js中编写。

describe('Example', () => {
  beforeEach(async () => {
    await device.reloadReactNative();
  });

  it('should have welcome screen', async () => {
    await expect(element(by.id('welcome'))).toBeVisible();
  });

  it('should show hello screen after tap', async () => {
    await element(by.id('hello_button')).tap();
    await expect(element(by.text('Hello!!!'))).toBeVisible();
  });

  it('should show world screen after tap', async () => {
    await element(by.id('world_button')).tap();
    await expect(element(by.text('World!!!'))).toBeVisible();
  });
});

上述是detox帮我们自动生成的一段代码,describe相当于testsuit,后面跟的是testsuit名称(建议与项目名称一致),it 相当于testcase,后面跟的是testcase名称。

detox的每一个步测试方法都是 async 的, 例如当 hello_button 被点击之后,App 的各种线程, animation, 网络请求, 异步方法等等统统运行完毕,App 完全空闲的时候 tap 方法才会resolve。

因此当测试运行到第二步的时候, word_button 一定是处于可点击状态的, 不需要再用sleep或者wait方法来保证 word_button 的状态。 这就是 自动同步(Automatically synchronized 同步指测试脚本和 App 的执行是按预期顺序执行的)。

编写测试用例 

device

await device.reloadReactNative();

设备在每个测试文件中全局可用,它可以控制当前连接的设备(目前仅支持模拟器)。detox 提供了丰富的api:

获取组件

通过by.id('xxx')获取组件,并执行相应的操作。获取组件的方式有如下几种:

  • by.id() 通过ID查找组件
  • by.text() 通过文本查找组件
  • by.label() 通过label查找组件 (只支持iOS)
  • by.type() 通过组件类型查找组件 (不建议使用,Android 和 iOS 端类型不一致)
  • by.traits() 不建议使用
  • Advanced  组合使用,例如:element(by.id('welcome').and(by.text('welcome')

所以,大部分情况下我们都使用 by.id。by.id会对应于JSX中的testID属性。看下面的例子

<Text testID={'welcome'} style={styles.welcome}>Welcome to React Native!</Text>
await expect(element(by.id('welcome')))

查找组件后,我们可以模拟什么操作呢?

 可见,detox为们提供了很丰富的模拟操作,点击、长按、双击、清除、滑动切换,滚动等等。以下是简单的例子: 

await element(by.id('tappable')).tap();  

await element(by.id('tappable')).longPress();

await element(by.id('tappable')).multiTap(3);

await element(by.id('tappable')).tapAtPoint({x:5, y:10});

await element(by.id('textField')).typeText('passcode');

await element(by.id('textField')).replaceText('passcode again');

await element(by.id('textField')).clearText();

await element(by.id('scrollView')).scroll(100, 'down');

await element(by.id('scrollView')).scroll(100, 'up');

await element(by.id('scrollView')).scrollTo('bottom');

await element(by.id('scrollView')).scrollTo('top');

await element(by.id('scrollView')).swipe('down');

await element(by.id('scrollView')).swipe('down', 'fast');

await element(by.id('scrollView')).swipe('down', 'fast', 0.5);

await expect(element(by.type('UIPickerView'))).toBeVisible();

await element(by.type('UIPickerView')).setColumnToValue(1,"6");

await element(by.type('UIPickerView')).setColumnToValue(2,"34");

detox 使用 Matchers 在您的应用中查找UI元素,使用动作模拟用户与这些元素的交互,使用 Expectations 来验证这些元素的值。expect 函数会验证某个值是否符合预期。

await expect(element(by.text('Hello!!!'))).toBeVisible();

 同样,detox 提供了丰富的验证方式:

await expect(element(by.id('UniqueId204'))).toBeVisible();

await expect(element(by.id('UniqueId205'))).toBeNotVisible();

await expect(element(by.id('UniqueId205'))).toExist();

await expect(element(by.id('RandomJunk959'))).toNotExist();

await expect(element(by.id('UniqueId204'))).toHaveText('I contain some text');

await expect(element(by.id('UniqueId204'))).toHaveLabel('Done');

await expect(element(by.text('I contain some text'))).toHaveId('UniqueId204');

await expect(element(by.id('UniqueId533'))).toHaveValue('0');

构建执行用例

测试用例编写完成后,接下来就是要验证的时刻。detox-cli 提供了 build 来执行App的构建操作。还记得刚开始我们在package.json 中对 detox 的 ios.sim.debug 配置吗?没错,detox build 就是会去执行该配置下面的build。而我们也可以继续增加自己的配置,例如:ios.sim.release 等等。

构建

detox build --configuration ios.sim.debug (debug模式)

detox build --configuration ios.sim.release (release模式)

执行用例

detox test --configuration ios.sim.debug (debug模式)

detox test --configuration ios.sim.release (release模式)

⚠️注意事项

(1)版本问题:node >= 8.3.0
(2)testID 的问题:全局统一,及时在不同的页面不能用同一个testID
(3)当页面太长的时候,某些元素在页面的没有显示出来,这时需要 用swipe 或者是scroll 来模拟一个向上拖动页面的过程,使被测试的元素显示出来才能进行测试
(4)有时候 模拟器上的键盘连接到Mac 的键盘,默认隐藏 模拟器的键盘,需要手动调出 模拟器的键盘,不然 测试中一些需要输入文字的测试会挂。。。CI 上这个问题常见,一直想办法通过程序代码的方式使模拟器使用自己的键盘。

(5)react-navigation 路由导航,侧滑返回需要禁掉。

以上就是关于 React Native Detox 测试的内容,希望对你有所帮助。

发布了214 篇原创文章 · 获赞 371 · 访问量 92万+

猜你喜欢

转载自blog.csdn.net/u013718120/article/details/90272863