
已经加注释了,你看一下吧:
lblStatusText = "执行中,请稍候……";Func<int> longTask = new Func<int>(delegate()
{
// 模拟长时间任务
ThreadSleep(2000);
// 返回任务结果:5
return 5;
});
// 发起一次异步调用,实际上就是在net线程池中执行longTask
// 这时由于是其它线程在工作,UI线程未被阻塞,所以窗体不会假死
longTaskBeginInvoke(ar =>
{
// 使用EndInvoke获取到任务结果(5)
int result = longTaskEndInvoke(ar);
// 使用ControlInvoke方法将5显示到一个label上,如果没有Invoke,
// 直接写lblStatusText="5",将会抛出跨线程访问UI控件的异常
Invoke(new Action(() => lblStatusText = "执行结果是:" + result));
}, null);
Google在sdk40以后提供了一个自动化解决方案uiautomator:
优点:可以跨应用了;这可是亲生的;
缺点:必须sdk40以上版本;要想实现的好,最好有开发配合;java项目编译为jar后需要push到手机才能运行,也就是说必须打印日志暴力调试。
Appium基于Android InstrumentationFramework和UIAutomator,也就是说这个工具是可以跨应用的。说远了,好吧,为了帮大家更容易理解appium的使用,我这里就讲一下uiautomator的使用方法。
你应该有android-sdk吧,升级到40以上,进入目录android-sdk\tools,你会看到两个文件:
traceviewbat 和 uiautomatorviewerbat,这俩文件让你想起了monkeyrunner了吧,是的,traceviewbat就对应于hierarchyviewerbat,用来查看程序的ui界面的,通常也是使用管理员权限启动的。
好了,现在用eclipse创建一个java project,是的,你没看错,是java project不是android project,添加引用:
在projectproperties中内容为:
# Project target
target= android-16
这里的android-16需要和之前的androidjar和uiautomatorjar位置相一致。
然后呢?写代码吧,建立一个类,得,发个给大家参考:
package comuiaexamplemy;
import orgapache>
import androidgraphicsBitmap ;
import androidgraphicsBitmapFactory ;
import androidgraphicsRect ;
import androidosEnvironment;
import comandroiduiautomatorcoreUiObject;
import comandroiduiautomatorcoreUiObjectNotFoundException;
import comandroiduiautomatorcoreUiScrollable;
import comandroiduiautomatorcore UiSelector ;
import comandroiduiautomatortestrunnerUiAutomatorTestCase;
import javaioFile;
import javaioFileOutputStream;
import javaioIOException;
public class TAppWorkAssistV1 extends UiAutomatorTestCase {
public String sLog ;
public File fout = null ;
public FileOutputStream outStream = null ;
public void write2file(String filename,String sData)
{
String sLog= "" ;
// 初始化日志文件
if (Environment getExternalStorageState ()equals(EnvironmentMEDIA_MOUNTED )){
sLog = Environment getExternalStorageDirectory()getAbsolutePath();
try {
fout = new File(sLog,filename);
outStream = new FileOutputStream( fout , true ); // 此处的 true 是append
sData=sData + "\n" ;
outStream write(sDatagetBytes());
outStream flush();
outStream close();
fout = null ;
}
catch (Exception e){
eprintStackTrace();
}
} else {
System out println( " 该手机没有 SD 卡 " );
}
}
public void testDemo() throws UiObjectNotFoundException {
//1 启动 app
getUiDevice()pressHome();
UiObject allAppsButton = new UiObject( newUiSelector()description( "Apps" ));
allAppsButtonclickAndWaitForNewWindow();
UiObject appsTab = new UiObject( new UiSelector()text( "Apps" ));
appsTabclick();
UiScrollable appViews = new UiScrollable( newUiSelector()scrollable( true ));
UiObject settingsApp = appViewsgetChildByText( newUiSelector()className(androidwidgetTextView class getName()), "Efilm" );
settingsAppclickAndWaitForNewWindow();
//2 进入主界面
System out println( "into main view" );
System out println(getUiDevice()waitForWindowUpdate("comeshoreefilm" , 60000));
System out println( "intoed main view" );
UiObject tv1 = new UiObject( new UiSelector()text( " 影院 " ));
tv1click();
//3 点击影院
UiObject oyy= new UiObject( new UiSelector()description("cinema_row" ));
System out println( "wait yingyuan come out" );
oyywaitForExists(60000);
System out println( "yingyuan come out" );
oyyclickAndWaitForNewWindow();
System out println( "click yingyuan" );
//4 场次
UiObject occ= new UiObject( new UiSelector()description("LinearLayout10" ));
System out println( "wait changci come out" );
oyywaitForExists(60000);
System out println( "changci come out" );
occclickAndWaitForNewWindow();
System out println( "click changci" );
//5 座位
UiObject oseat= new UiObject( new UiSelector()description("cinema_shows_list_item" )index(0)childSelector( newUiSelector()description( "LinearLayout10" )));
System out println( "wait seat come out" );
oseatwaitForExists(5000);
int h=getUiDevice()getDisplayHeight();
int w=getUiDevice()getDisplayWidth();
System out println( "(h/2,w/2)=" +h/2+ "," +w/2);
getUiDevice()click(h/2,w/2);
//Systemoutprintln("seat count:"+StringvalueOf(oseatgetChildCount()));
//Systemoutprintln("seat getText:"+ oseatgetText());
// 截座位图
Process process;
try {
process = Runtime getRuntime ()exec( "screencap /mnt/sdcard/EfilmFailSnapShot01png" );
try {
processwaitFor();
} catch (InterruptedException e) { // TODO Auto-generated catch block
eprintStackTrace();
}
} catch (IOException e) {
// TODO Auto-generated catch block
eprintStackTrace();
}
//takeScreenShots("EfilmSeatSnapShot");
}
}
这个例子是随便写的,可能不够严谨。大体就这么个情况吧。下一步就是编译执行了,先插上手机usb接口,然后打开cmd,执行:
找到SDKID,也就是android create中的-t参数:
cd C:\ PROGRAM\android-sdk\tools
android list
找到t参数的值以后:
cd C:\ PROGRAM\android-sdk\tools
android create uitest-project -n TAppWorkAssistV1 -t 25 -p C:\android自动化\Tv20\TestSetting
cd C:\android自动化\Tv20\TestSetting
ant build
cd C:\android自动化\Tv20\TestSetting\bin
adb push TAppWorkAssistV1jar /data/local/tmp/
adb shell uiautomator runtest TAppWorkAssistV1jar -c comuiaexamplemy TAppWorkAssistV1
看了看,好像没有什么特别值得解释的
-n TAppWorkAssistV1:类名
-p: 项目所在目录
Ant build 把这个类编译成一个jar包:TAppWorkAssistV1jar
然后把jar包push到手机上,调用执行这个类就可以了
大致是这么个步骤,不过有一个非常重要的细节,就是如果你需要更省心,就最好把界面元素,无论动态的还是布局文件中的,都加上content-description属性,并保证唯一性,根据:
UiSelector:description(String desc)
Set the search criteria to match thecontent-description property for a widget
那就可以统一只使用这一个引用界面元素的方法就行了,就不用去想方设法利用其它的属性来引用了。
先来看下未使用 PO(PageObject) 设计模式下的代码,以网页版百度登录为例来说明。
非 PO(PageObject) 模式下的代码如下,所有内容全部写在一个方法里。
存在的问题:
PO(PageObject) 模式优化后的代码
1、WebUI 自动化需要的 driver 基础 *** 作
2、登录页面元素获取
3、登录逻辑业务的封装
4、登录测试用例将使用以上3个页面对象
可以发现,使用 PO(PageObject) 模式优化后的代码,有以下明显优势:
1)、将以下3个模块进行了单独封装 降低了模块之间的耦合度,使层次更加清晰合理,便于后期维护与复用:
2)、如果前端页面有 定位元素的 type 或 value 发生变化时,只需要修改 elementspy 文件中元素信息即可 ,不需要在测试业务模块中进行修改。
以上就是关于c# 通过异步委托的执行结果更新UI界面全部的内容,包括:c# 通过异步委托的执行结果更新UI界面、用android uiautomator做自动化测试,怎么连接真机进行、WebUI 自动化测试的经典设计模式:PO等相关内容解答,如果想了解更多相关内容,可以关注我们,你们的支持是我们更新的动力!
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)