用脚教你使用Appium自动测试你的React Native
theme: smartblue highlight: a11y-dark
| Appium[ æpi'ʌm ]
Appium是一款开源测试工具,可以用来测试安卓/iOS/Windows端的原生应用和Web混合应用。
工作原理
Appium有一个客户端-服务器架构。Appium客户端向Appium服务器(一个Node.js HTTP服务器)发送请求,反过来,Appium服务器向执行动作的设备发送请求。然后,服务器将结果返回给客户端,让你知道测试的状态。
功能
- 跨平台
- 多开发语言支持
- 不需要重新编译应用程序
- 不需要重复找轮子,可共用API
- 市场占有率TOP1
优点
- 方便的切换测试原生应用或App内嵌的web页面,对Hybrid App友好
- 使用各个平台自身提供的测试框架,因此无需引入第三方代码或重新打包应用
- 开源,维护频率很高,社区也有相对较高的活跃度
- 支持通过自定义插件寻找元素
缺点
- 不支持单元测试、跨应用测试
- 测试效率相对较低
使用
默认您已经安装node以及对应的Android或IOS等相关环境
使用appium
有两种方式:
方式1:npm
方式2:下载Appium Desktop,这是一种基于图形的、基于桌面的方式来启动 Appium 服务器。
这里主要介绍npm的使用方式
step 1: 安装appium
npm install -g appium
step 2: 安装webdriverio
npm install --save webdriverio @wdio/cli
webdriverio是什么?
基于Node.js的下一代浏览器和移动自动化测试框架
生成 Web 驱动程序配置文件以在测试时应用配置
step 3: 配置webdriverio
执行npx wdio config
生成的文件目录如下
及wdio.conf.js
配置文件
复制并修改有注释的字段到你的wdio.config.js
文件
javascript
exports.config = {
port: 4723,
services: [['appium', {command: 'appium'}]],
runner: 'local',
specs: ['./test/specs/**/*.js'], // 测试目录
maxInstances: 1,
capabilities: [
{
maxInstances: 1,
browserName: '',
appiumVersion: '1.22.3', // appium -v 获取
platformName: 'Android',
platformVersion: '9', // 安卓版本
deviceName: 'Nexus_S_API_28', // 设备名称 执行adb -s emulator-5554 emu avd name 获取
app: './android/app/build/outputs/apk/debug/app-debug.apk', // apk目录, 没有的话先在Android studio build一个
automationName: 'UiAutomator2',
},
],
logLevel: 'trace',
bail: 0,
waitforTimeout: 10000,
connectionRetryTimeout: 90000,
connectionRetryCount: 3,
framework: 'mocha',
reporters: ['dot'],
mochaOpts: {
ui: 'bdd',
timeout: 60000,
},
};
step 4: 创建一个测试用例
修改test/specs/example.e2e.js
文件
```javascript
describe('Simple App testing', () => {
beforeEach(async () => {
const app = await $('~app-root');
await app.waitForDisplayed(10000, false);
});
it('Login test: valid case', async () => { const username = await $('~username'); await username.setValue('codemagic'); const password = await $('~password'); await password.setValue('nevercode');
const loginBtn = await $('~login');
await loginBtn.click();
await $('~loginstatus').waitForDisplayed(11000);
const status = await $('~loginstatus').getText();
expect(status).toHaveValueContaining('登录成功');
});
it('Login test: invalid case', async () => { await $('~username').setValue('nevercode'); await $('~password').setValue('codemagic');
await $('~login').click();
await $('~loginstatus').waitForDisplayed(11000);
const status = await $('~loginstatus').getText();
expect(status).toHaveValueContaining('未登录'); // 断言https://webdriver.io/docs/api/expect-webdriverio
}); }); ```
step 5: 创建一个app页面
如图:
修改你的App.js
```javascript
import React, {Component} from 'react';
import {
TouchableHighlight,
StyleSheet,
Text,
TextInput,
View,
} from 'react-native';
export default class App extends Component { constructor() { super(); this.state = { username: '', password: '', isLogined: false, }; }
inputChangeHandler = (value, name) => { this.setState({ [name]: value, }); };
login = () => { if ( this.state.username === 'codemagic' && this.state.password === 'nevercode' ) { this.setState({isLogined: true}); } else { this.setState({isLogined: false}); } };
render() {
return (
<View style={LOCAL_STYLES.inputContainer}>
<TextInput
name="password"
accessibilityLabel="password"
secureTextEntry={true}
style={LOCAL_STYLES.input}
onChangeText={text => this.inputChangeHandler(text, 'password')}
/>
</View>
<Text accessibilityLabel="loginstatus">
{this.state.isLogined ? '登录成功' : '未登录'}
</Text>
<TouchableHighlight
style={LOCAL_STYLES.buttonContainer}
accessibilityLabel="login"
onPress={this.login}>
<Text style={{color: 'white'}}>Login</Text>
</TouchableHighlight>
</View>
);
} }
const LOCAL_STYLES = StyleSheet.create({ wrapper: { flex: 1, alignItems: 'center', justifyContent: 'center', },
inputContainer: { borderBottomColor: '#AFAFAF', backgroundColor: '#FFFFFF', borderRadius: 10, borderBottomWidth: 1, marginBottom: 16, flexDirection: 'row', alignItems: 'center', width: '80%', borderColor: 'blue', borderWidth: 1, }, buttonContainer: { height: 45, width: 250, flexDirection: 'row', justifyContent: 'center', alignItems: 'center', marginBottom: 20, borderRadius: 20, backgroundColor: '#00b5ec', }, }); ```
step 6: 编译你的应用到模拟器
yarn android
yarn start
step 7: 执行测试用例
npx wdio ./wdio.conf.js
执行通过后会有passed的打印
**Spec Files: 1 passed, 1 total (100% completed) in 00:00:32**
至此,测试结束
Q&A
如何来标识RN组件?
对于 Android,添加accessibilityLabel属性
对于 iOS,添加testID属性
javascript
<View style={LOCAL_STYLES.inputContainer}>
<TextInput name="password" accessibilityLabel="password" testID='password' secureTextEntry={true} style={LOCAL_STYLES.input} onChangeText={(text) => this.inputChangeHandler(text, "password")} />
</View>
然后在测试脚本通过$('~password')
获取
更多标识用法参考官方文档Selector
| 参考资料
# Appium自动化环境搭建保姆级教程
# Appium mobile testing – test React Native apps