Android和Appium自学自测(一)
来源:互联网 发布:房产中介端口 编辑:程序博客网 时间:2024/05/03 17:27
背景
本来今年计划是要把Android和iOS都学一下,结果现在到年底了,还是没点苗头,再怎样也应该开个头,于是就买了《第一行代码(第二版)》开始学习Android,在学习的过程中,利用Appium来测试自己写出来的东西,也不失为一个学习的方法。
项目Github地址:https://github.com/diandianhanbin/LearnAndroidDoAppium
TextView
这个控件对应着HTML的Label,其实可以理解为一个标签,用来展示文本内容,当然,它也可以监听点击,所以在某种程度上来说,也可以发挥一个按钮的作用。
<TextView android:id="@+id/text_view" android:layout_width="match_parent" android:layout_height="wrap_content" android:textSize="24sp" android:gravity="center|center_horizontal" android:text="This is a TextView!" />
TextView
控件可以定义id
,这个id
无论对于开发还是测试,都是很有用的东西,开发的时候,可以通过id来对控件监听、设置等操作。
比如下面的代码就是用来关联和设置TextView
。
textView = (TextView) findViewById(R.id.text_view);case R.id.changeTextView: if (textView.getText().toString() == "Change Text") { textView.setText("This is a TextView"); } else { textView.setText("Change Text"); } break;
对于测试来说,这个控件就是获取文本最方便的地方。利用uiautomatorviewer
我们可以很直接的获取这个控件的resource-id
注:resource-id的组成是 包名 + / + id
在使用Appium测试的过程中获取的方式就是这样的
TextView = methodConfig.SIMPLEREAD['TextView']def getTextView(self): """ 获取TextView :return:str, 标题文本 """ return self.getTextOfElement(*self.TextView)class MessageSimpleRead(AppiumBaseTest, SimpleRead): def test001_checkTextView(self): """测试TextView内容是否正确""" textcontent = self.getTextView() self.assertEqual('This is a TextView!', textcontent)
Activity
Activity
应该是Android的非常重要的东西,属于Android的四大组件之一。
简单的来理解,Activity
可以理解为一个HTML
页面,Android所有的显示,都是由Activity
来承载,关于Activity
的信息就不多写了,在网络上很多,主要需要熟悉它的生命周期.
这里我用按钮来触发跳转第二个Activity
,所以在测试的时候需要测试这个跳转。
Android部分是一个显式启动,代码如下:
@Override public void onClick(View v) { Intent intent = new Intent(MainActivity.this, SecondActivity.class); startActivity(intent); }
对应的Appium的操作方法如下:
SecondActivity = methodConfig.SIMPLEREAD['SecondActivity']def clickButtonStartActivity(self): """ 点击按钮启动Activity :return: """ self.clickElement(*self.ButtonStartActivity) def checkSecondActivity(self): """ 检查是否启动第二个Activity :return: True or False """ return self.waitActivity(self.SecondActivity)def test003_changeActivity(self): """跳转Activity测试""" self.clickButtonStartActivity() self.assertEqual(self.checkSecondActivity(), True) self.assertEqual(self.getSecondActivityTextView(), u'This is Second Activity')
当然,通过Appium
还有其他方法启动Activity
,源码中对应的还有这个方法:
def start_activity(self, app_package, app_activity, **opts): """Opens an arbitrary activity during a test. If the activity belongs to another application, that application is started and the activity is opened. This is an Android-only method. :Args: - app_package - The package containing the activity to start. - app_activity - The activity to start. - app_wait_package - Begin automation after this package starts (optional). - app_wait_activity - Begin automation after this activity starts (optional). - intent_action - Intent to start (optional). - intent_category - Intent category to start (optional). - intent_flags - Flags to send to the intent (optional). - optional_intent_arguments - Optional arguments to the intent (optional). - stop_app_on_reset - Should the app be stopped on reset (optional)? """ data = { 'appPackage': app_package, 'appActivity': app_activity } arguments = { 'app_wait_package': 'appWaitPackage', 'app_wait_activity': 'appWaitActivity', 'intent_action': 'intentAction', 'intent_category': 'intentCategory', 'intent_flags': 'intentFlags', 'optional_intent_arguments': 'optionalIntentArguments', 'stop_app_on_reset': 'stopAppOnReset' } for key, value in arguments.items(): if key in opts: data[value] = opts[key] self.execute(Command.START_ACTIVITY, data) return self
不过正常来说,不建议这么处理,因为这样处理,就没有覆盖到点击按钮跳转Activity
这个业务场景了。
Menu
系统的Menu
对测试来说绝对一个大坑。
从开发上来看,是一个非常正常的开发流程,在xml
中写一个menu
的布局、控件名称和控件ID。然后在需要展示Menu
的Activity
中调用如下方法即可生成Menu
:
@Override public boolean onCreateOptionsMenu(Menu menu) { getMenuInflater().inflate(R.menu.main, menu); return true; }
这是一个再正常不过的开发方式了,但是到了测试这里,完全就是一个深坑。
比如,我在定义这个Menu
的时候,用的id
是这样的:
<menu xmlns:android="http://schemas.android.com/apk/res/android" android:id="@+id/main_menu"></menu>
但是用uiautomatorviewer
来查看的时候,它给我显示的却是这个
WTF!!!这个菜单竟然是一个ImageView
,然后,我定义的id
呢?被Android吃了么????
然后再看这个菜单栏。。。。从uiautomatorviewer
上来看,是由一个一个的ListView
组成的,这些我不关心,作为测试,我关心的依然是它的id
。
从uiautomatorviewer
探测的结果是com.example.svenweng.uiwidgettest:id/title
。可是,我特么开发的时候,定义的是这样的啊啊啊啊!!!
<item android:id="@+id/getTextView" android:title="@string/main_menu_getTextView"/> <item android:id="@+id/changeTextView" android:title="@string/main_menu_changeTextView"/> <item android:id="@+id/changeImageView" android:title="@string/main_menu_changeImageView"/> <item android:id="@+id/changeProgressBar" android:title="@string/main_menu_changeProgressBar"/> <item android:id="@+id/insertProgressBar" android:title="@string/main_menu_insertProgressBar"/> <item android:id="@+id/delProgressBar" android:title="@string/main_menu_delProgressBar"/> <item android:id="@+id/alertDialog" android:title="@string/main_menu_alertDialog"/> <item android:id="@+id/alertProgressDialog" android:title="@string/main_menu_progressDialog"/>
Android你全部给我改成com.example.svenweng.uiwidgettest:id/title
是几个意思????
在开发调用对应菜单监控的时候,用的也是它的id
啊!!!
switch (item.getItemId()) { case R.id.getTextView: Toast.makeText(this, textView.getText().toString(), Toast.LENGTH_SHORT).show(); break; case R.id.changeTextView: if (textView.getText().toString() == "Change Text") { textView.setText("This is a TextView"); } else { textView.setText("Change Text"); } break; case R.id.changeImageView: imageView.setImageResource(R.drawable.img_1); break; case R.id.changeProgressBar: if (progressBar.getVisibility() == View.GONE) { progressBar.setVisibility(View.VISIBLE); } else { progressBar.setVisibility(View.GONE); } break; case R.id.insertProgressBar: progress = progress + 10; oriProgressBar.setProgress(progress); break; case R.id.delProgressBar: progress = progress - 10; oriProgressBar.setProgress(progress); break; case R.id.alertDialog: AlertDialog.Builder dialog = new AlertDialog.Builder(MainActivity.this); dialog.setTitle("This is a Dialog"); dialog.setMessage("This is a Message"); dialog.setCancelable(false); dialog.setPositiveButton("OK", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "OK", Toast.LENGTH_SHORT).show(); } }); dialog.setNegativeButton("Cancel", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Toast.makeText(MainActivity.this, "Cancel", Toast.LENGTH_SHORT).show(); } }); dialog.show(); break; case R.id.alertProgressDialog: ProgressDialog progressDialog = new ProgressDialog(MainActivity.this); progressDialog.setTitle("This is a ProgressDialog"); progressDialog.setMessage("loading...."); progressDialog.setCancelable(true); progressDialog.show(); break; default: break;
为毛线在测试使用的时候,唯一的id
都变成了一样的东西啊!!!
最后
我一直坚持的观点,不懂开发就很难测试,从这一次的学习来看,我之前有很多想法是有一些问题的,以前我总是觉得开发为什么这么懒,控件不用就不加id
,或者老喜欢用同样的id
。现在我终于知道了,很多时候我都在错怪开发。
- Android和Appium自学自测(一)
- android基础自测题集锦(一)
- (Android开发自测)在Mac OS 10.12 上安装配置appium
- android自学笔记(一)
- android 自学日记(一)
- Android自学笔记(一)
- 配套自测连载(一)
- Appium实践(一)
- Android 全自动js脚本测试 Appium教程——appium环境搭建(一)
- Android之自学笔记(一)
- Appium在Android平台实战训练(一)
- 一键配置Java环境(Android,Appium,python等)
- css自问自测题(一)
- Java序列化框架自测(一)
- appium 环境配置(一)
- 搭建appium环境(一)
- android中级自测题(二)
- Appium的一点一滴:Appium 和Android真机
- How Android Draws Views,Android如何绘制View,
- 初始化数据库数据到内存(实质保存到java对象)
- 使用plsql连接oracle一样,使用ClouderaImpalaODBC32.msi工具连接impala的方法!
- java中log日志的使用
- NSInteger问题
- Android和Appium自学自测(一)
- Java synchronized详解
- 简要描述 JavaScript 中定义函数的几种方式
- Oracle 数据库文件的导入导出
- HDFS工作原理(1.0)
- web.xml配置中的log4jRefreshInterval讲解
- IOS合成多个视频和音频文件时闪退
- strncat用法
- iOS开源项目周报1229