首页 文章 精选 留言 我的

精选列表

搜索[自动装配],共10000篇文章
优秀的个人博客,低调大师

Apache Ant 1.10.12 发布,自动化构建工具

Apache Ant 1.10.12 已发布。 目前 Apache Ant 团队正在维护两个分支,分别是 1.9.x 和 1.10.x。前者要求 Java 5 以上,后者要求 Java 8 以上。1.9.x 系列主要是修复 bug,1.10.x 会增加新功能,两个分支都基于 Ant 1.9.7。除非在构建过程中要求 Java 8 之前的版本,否则最好还是使用官方推荐的 1.10.x 分支。 此次发布的 1.10.12 主要是修复 bug。 已修复的错误 即便"followRedirects"属性被设置为"false",http condition 也会跟随重定向。此问题现已修复。 确保将 build.compiler 设置为与 extJavac 或现代相对应的完全限定类名,与使用较短的别名具有相同的效果 防止 org.apache.tools.ant.IntrospectionHelper 中的潜在死锁 其他变更 修改 AntClassLoader#findResources() 方法的实现,优化其潜在的性能问题。详情点此查看 AntClassLoader 已实现 ClassLoader#findResource(String) 方法 Ant 在可能的情况下会尽量避免文件名的规范化 (file name canonicalization) 当"failonwarning"设置为 true 时,javadoc task 会在 STDERR stream 中寻找警告信息 tar task 现已支持保留嵌套 tarfilesets 的符号链接 下载地址 https://ant.apache.org/bindownload.cgi(二进制文件) https://ant.apache.org/srcdownload.cgi(源代码)

优秀的个人博客,低调大师

python pip之python模块自动化安装脚本

此脚本集成pip所有功能,可在远程环境中执行,为你解决还在忧愁记住pip命令烦恼,此脚本预留了接口,可根据自己的实际环境自定义开发。 defpip_python_file(): win=(sys.platform=='win32') linux=(sys.platform=='linux2') ifwin: version=subprocess.Popen('pip-V',stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() iflen(version)>0: print('********************安装环境信息********************') try: print('win_version:') print('\t'+u'版本:%s'%platform.platform()) exceptException: print() pip_version=subprocess.Popen('pip-V', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.readlines() python_version=subprocess.Popen('python-V', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.readlines() python_path=subprocess.Popen('wherepython', stdout=subprocess.PIPE, stderr=subprocess.PIPE, shell=True).stdout.readlines() forpython_version1inpython_version: print('python_version&path:') print('\t'+u'版本:%s'%str(python_version1,encoding="utf8").strip()) forpython_path1inpython_path: print('\t'+u'路径:%s'%str(python_path1,encoding="utf8").strip()) forpip_version1inpip_version: print('pip_version&path:') print('\t'+u'版本:%s'%str(pip_version1,encoding="utf8").strip()[:11]) print('\t'+u'路径:%s'%str(pip_version1,encoding="utf8").strip()[16:]) defmenu(): print("****************Pythonpip安装工具1.0****************") print('1.添加py模块') print('2.卸载py模块') print('3.查询更新py模块') print('4.查询单个py模块') print('5.查询所有py模块') print('6.pip使用方法') print('7.更新py模块') print('8.退出pip工具') print('9.查看本电脑环境变量') definput_card(): """ 1.添加py模块 :return: """ try: print('***************添加py模块***************') out=input('输入模块名称:') add_pip="pipinstall" add_pip1=subprocess.Popen(add_pip+'\t'+out,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() foriinadd_pip1: print('\t'+str(i,encoding="utf8").strip()) exceptExceptionase: print("错误日志:"+str(e)) else: print() whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() defdel_name(): """ 2.卸载py模块 :paramcard_list: :return: """ try: print('***************卸载py模块***************') out=input('输入卸载模块名称:') add_pip="pipuninstall" add_pip1=subprocess.Popen(add_pip+'\t'+out,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() foriinadd_pip1: print('\t'+str(i,encoding="utf8").strip()) exceptExceptionase: print("错误日志:"+str(e)) else: print() whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() defdel_card(): """ 7.更新py模块 :return: """ try: print('***************更新py模块***************') out=input('输入需要更新模块名:') add_pip="pipinstall-U" add_pip1=subprocess.Popen(add_pip+'\t'+out,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() foriinadd_pip1: print('\t'+str(i,encoding="utf8").strip()) exceptExceptionase: print("错误日志:"+str(e)) else: print() whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() deffind_name(): """ 4.查询已安装模块 :paramcard_list: :return: """ t=input('输入查询模块名称:') importsys defdump(module): print("{0}模块安装路径".format(module)) ifmoduleinsys.builtin_module_names:#查找内建模块是否存在 print("") else: module=__import__(module)#非内建模块输出模块路径 print('(非内置模块已安装)安装路径:%s'%module.__file__) dump(t) whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() defedit_name(): """ 3.需要升级模块 :paramcard_list: :return: """ update_pip="piplist--outdated" update_pip1=subprocess.Popen(update_pip,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() print(u'需要升级模块:') foriinupdate_pip1: print('\t'+str(i,encoding="utf8").strip()) whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() defsee_card(): """ 5.查看所有安装py模块 :paramcard_list: :return: """ cat_pip="piplist" cat_pip1=subprocess.Popen(cat_pip,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() print(u'你已安装的模块:') foriincat_pip1: print('\t'+str(i,encoding="utf8").strip()) whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() defpip_help(): """ 6.退出系统 :return: """ sys.exit('感谢使用本工具!!!') defsign_out(): """ 8.pip参数使用方法 :paramcard_list: :return: """ update_pip="pip" update_pip1=subprocess.Popen(update_pip,stdout=subprocess.PIPE,stderr=subprocess.PIPE, shell=True).stdout.readlines() print(u'pip参数使用方法:') foriinupdate_pip1: print('\t'+str(i,encoding="utf8").strip()) whileTrue: niu=input("请继续您的选择是(y/q):").strip() ifniu=='y': returnmain() elifniu=='q': exit('/n你已退出程序...') else: print("输入错误,请重新输入") returnmain() defpip_path(): importos print(u'本地电脑环境变量:') print('\t'+'PATH='+os.environ['path']) defmain(): menu() whileTrue: mun=input('请输入功能序号:') ifmun.isdigit(): mun=int(mun) else: print('请输入正确的功能序号!') ifmun==1: input_card() ifmun==2: del_name() ifmun==3: edit_name() ifmun==4: find_name() ifmun==5: see_card() ifmun==6: sign_out() break ifmun==7: del_card() ifmun==8: pip_help() ifmun==9: pip_path() if__name__=='__main__': card_list=[] main() else: print('请先安装pip或配置环境变量') else: print('请先安装pip或配置环境变量') frombs4importBeautifulSoup text=""" pip安装方法""" soup=BeautifulSoup(text,'html.parser') href=soup.find('a').get('href') print('pip安装方式:',href) iflinux: pass else: print('请先安装pip或配置环境变量')

优秀的个人博客,低调大师

Java自动化测试(Android app界面元素 33)

App分类 Native App 原生App 优点 直接依托于操作系统,交互性最强,性能最好,功能最为强大 缺点 开发成本高,更新缓慢,审核周期慢,维护成本高 Hybrid App 混合型App 优点 开发成本较低,可以跨平台,调试方便,维护成本低,功能可复用,性能和体验要比web app好,更新较自由 缺点 相比原生性能仍有较大损耗,不适用于交互性较强的app Web App 使用浏览器展示 优点 开发成本低,可以跨平台,调试方便,更新无需通知用户,不需要手动升级,无需安装App,不会占用手机存储空间 缺点 无法获取系统级别的通知/提醒/动效等,用户留存率低,体验差,设计受限较多 如何区分 开启显示布局界面,当看到出现方框则使用的是原生 定位 ActivityName & PackageName PackageName「包名」 应用的唯一身份标示,系统通过包名识别不同的应用,如两个相同包名的应用在安装时会提示覆盖 ActivityName「类名」 Activity:android四大组件之一,就是一个和用户交互的界面 $adbshelldumpsysactivity|grep"mFocusedActivity"#Android8以上$adbshelldumpsysactivity|grep"mResumedActivity" 查找当前Activity 启动入口appActivity和Activity的区别: appActivity在App中是唯一的,它的作用是用来启动app的 $aaptdumpbadgingD:\apk\base.apk|find"launchable-activity" App页面布局 布局类型 框架布局 所有控件都被放置在左上的区域 下一个子控件会重叠覆盖上一个控件 线性布局 控件的排序方式:垂直/水平 绝对布局 采用坐标轴的方式定位控件 左上角(0,0) 往右x+ 往下y+ 相对布局 根据参照物的位置,来确定控件的位置 表格布局 通过表格的行列布局控件位置 元素定位 打开uiautomatorviewer $cd/Users/zhongxin/Library/Android/sdk/tools/bin$shuiautomatorviewer uiautomatorviewer id定位 resource-id定位,App是允许「resource-id」相同,如果有相同的resource-id,那么获取第一个元素 androidDriver.findElement(MobileBy.id("com.lemon.lemonban:id/category_title")).click(); text定位 androidDriver.findElement(MobileBy.AndroidUIAutomator("newUiSelector().text(\"全程班\")")).click(); className定位 类似web tagName找到元素类型 androidDriver.findElement(MobileBy.className("android.widget.TextView")).click(); Xpath定位 androidDriver.findElement(MobileBy.xpath("//android.widget.TextView[@text='全程班']")).click();androidDriver.findElement(MobileBy.xpath("//android.widget.FrameLayout[@resource-id='com.lemon.lemonban:id/navigation_tiku']")).click(); 坐标定位 TouchActiontouchAction=newTouchAction(androidDriver);PointOptionpointOption=PointOption.point(445,1539);touchAction.press(pointOption).release().perform(); toast元素定位 Toast是一种简单的消息提示框。当视图显示给用户,在应用程序中显示为浮动。和Dialog不一样的是,它永远不会获得焦点,无法被点击。 获取方式1:隐式等待 androidDriver.manage().timeouts().implicitlyWait(8,TimeUnit.SECONDS);androidDriver.findElement(MobileBy.xpath("//*[contains(@text,'错误的账号信息')]")); 获取方式2:显式等待 WebDriverWaitwait=newWebDriverWait(androidDriver,5);WebElementelement=wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.xpath("//*[contains(@text,'错误的账号信息')]")));element.getText(); 使用Appium定位 1.填写连接信息 填写连接信息 2. 启动会话 Appium 调试代码 packagecom.zhongxin.day03;importio.appium.java_client.MobileBy;importio.appium.java_client.TouchAction;importio.appium.java_client.android.AndroidDriver;importio.appium.java_client.touch.offset.PointOption;importorg.apache.tools.ant.taskdefs.Touch;importorg.aspectj.apache.bcel.ExceptionConstants;importorg.openqa.selenium.WebDriver;importorg.openqa.selenium.WebElement;importorg.openqa.selenium.remote.DesiredCapabilities;importorg.openqa.selenium.support.ui.ExpectedConditions;importorg.openqa.selenium.support.ui.WebDriverWait;importorg.testng.annotations.AfterTest;importorg.testng.annotations.BeforeTest;importorg.testng.annotations.Test;importjava.net.MalformedURLException;importjava.net.URL;importjava.util.concurrent.TimeUnit;publicclassElementLocator{privateAndroidDriverandroidDriver;@BeforeTestpublicvoidsetUp()throwsMalformedURLException{DesiredCapabilitiescapabilities=newDesiredCapabilities();capabilities.setCapability("platformName","Android");capabilities.setCapability("deviceName","127.0.0.1:62001");capabilities.setCapability("appPackage","com.lemon.lemonban");capabilities.setCapability("appActivity","com.lemon.lemonban.activity.WelcomeActivity");URLurl=newURL("http://127.0.0.1:4723/wd/hub");androidDriver=newAndroidDriver(url,capabilities);androidDriver.manage().timeouts().implicitlyWait(10,TimeUnit.SECONDS);}@Testpublicvoidtest01(){//androidDriver.findElement(MobileBy.id("com.lemon.lemonban:id/category_title")).click();//androidDriver.findElement(MobileBy.AndroidUIAutomator("newUiSelector().text(\"全程班\")")).click();//androidDriver.findElement(MobileBy.className("android.widget.TextView")).click();//androidDriver.findElement(MobileBy.xpath("//android.widget.TextView[@text='全程班']")).click();//androidDriver.findElement(MobileBy.xpath("//android.widget.FrameLayout[@resource-id='com.lemon.lemonban:id/navigation_tiku']")).click();//TouchActiontouchAction=newTouchAction(androidDriver);//PointOptionpointOption=PointOption.point(445,1539);//touchAction.press(pointOption).release().perform();androidDriver.manage().timeouts().implicitlyWait(8,TimeUnit.SECONDS);androidDriver.findElement(MobileBy.xpath("//*[contains(@text,'错误的账号信息')]"));WebDriverWaitwait=newWebDriverWait(androidDriver,5);WebElementelement=wait.until(ExpectedConditions.presenceOfElementLocated(MobileBy.xpath("//*[contains(@text,'错误的账号信息')]")));Stringtext=element.getText();System.out.println(text);}@AfterTestpublicvoidtearDown()throwsInterruptedException{Thread.sleep(2000);androidDriver.quit();}} 本文分享自微信公众号 - 测试游记(zx94_11)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

优秀的个人博客,低调大师

连载|想用Python做自动化测试?递归函数

“递归函数就是函数内部调用自身,可以使代码逻辑更加易懂。但是递归也有坑,需要避免。” 13.1 概念 在函数内部,可以调用其他函数。如果一个函数在内部调用自身,这个函数就是递归函数。 理论上,所有的递归函数都可以写成循环的方式,但循环的逻辑不如递归清晰。 计算阶乘n! = 1 x 2 x 3 x ... x n,用函数fact(n)表示: def fact(n): if n==1: return 1 return n * fact(n - 1) 13.2 写递归代码的套路 写递归代码的关键就是找到如何将大问题分解为小问题的规律,然后按照下面套路即可实现: 第一步,写出递推公式 以计算阶乘为例,递归公式是:fact(n)=n!=n×(n−1)×⋅⋅⋅3×2×1=n×(n−1)!=n×fact(n−1) 第二步,推敲终止条件 以计算阶乘为例,终止条件是n=1时,fact(1)=1。 13.2.1 斐波那契数列 再来看一个斐波那契数列的例子,斐波那契数列中后一个元素是前两个相邻元素的和。比如: 0,1,1,2,3,5,8,13,21,34,55,…。 那么我们如何得到第n个数是多少?分两步走: 第一步,写出递推公式。求第n个元素,可以先求出n-1和n-2个元素的值,然后再将这两个求和,所以公式是: fibonacci(n) = fibonacci(n - 1) + fibonacci(n - 2) 第二步,推敲最终终止条件。终止条件包含三个:n=0时,f(n)=0;n=1时,f(n)=1;n=2时,f(n)=1。 if n < 1: # 递归终止条件 return 0if n in [1, 2]: # 递归终止条件 return 1 转换成完整代码就是: def fibonacci(n): if n < 1: # 递归终止条件 return 0 if n in [1, 2]: # 递归终止条件 return 1 return fibonacci(n - 1) + fibonacci(n - 2) # 递归公式 不管是编写递归还是阅读递归代码,只要遇到递归,我们就把它抽象成一个递推公式,不用想一层层的调用关系,不要试图用人脑搞清楚计算机每一步都是怎么执行的。 13.2.2 n 个台阶有多少种走法 再来看看一个例子,假如有 n 个台阶,每次可以跨 1 个台阶或者 2 个台阶,请问走这 n 个台阶有多少种走法? 我们从第一步开始想,如果第一步跨1个台阶,问题就变成了n-1个台架有多少种走法。如果第一步跨2个台阶,问题就变成n-2个台阶有多少种走法。我们把n-1个台阶的走法和n-2个台阶的走法求和,就是n个台阶的走法。用公式表示就是f(n)=f(n-1)+f(n-2)。这就是递归公式了。 再来看看终止条件,最后1个台阶就不需要再继续递归了,只有一种走法,就是f(1)=1。我们把这个放到递归公式里面看下,通过这个终止条件能否求出f(2),发现f(2)=f(1)+f(0),也就是仅知道f(1)是不能求出f(2)的,因此要么知道f(0)的值,或者直接将f(2)作为一个递归终止条件。f(0)表示0个台阶有几种走法,f(2)表示2个台阶有几种走法。明显,f(2)更容易理解一些。所以定为f(2)=2也是一个终止条件,表示最后2个台阶有两种走法,即一次跨1个台阶和一次跨2个台阶。有了f(1)和f(2),就能求出f(3),进而求出f(n)了。 转化成代码即是: def walk(n): if n == 1: # 递归终止条件 return 1 if n == 2: # 递归终止条件 return 2 return walk(n - 1) + walk(n - 2) # 递归公式 13.3 递归可解决哪类问题 原始问题的解可以分解为几个子问题的解 原始问题和子问题,只有数据规模的不同,求解思路完全一样 存在递归终止条件 13.4 递归存在的问题 堆栈溢出 重复计算 编写递归代码时,我们会遇到很多问题,比较常见的一个就是堆栈溢出,而堆栈溢出会造成系统性崩溃,后果会非常严重。什么是堆栈溢出呢? 函数调用会使用栈来保存临时变量。每调用一个函数,都会将临时变量封装为栈帧压入内存栈,等函数执行完成返回时,再出栈。系统栈或者虚拟机栈空间一般都不大。如果递归求解的数据规模很大,调用层次很深,一直压入栈,就会有堆栈溢出的风险。 可以通过Pycharm工具查看调用栈的情况。在递归公式那行代码上添加断点,不断执行Step Over,可以看到Frames窗口中的栈信息会不断增加和减少,当调用一次函数会增加一帧,当调用返回后会减少一帧。最后返回第一层栈func.py。前面说的堆栈溢出的风险,体现在Frames窗口中的栈帧太多了。 那么,如何避免出现堆栈溢出呢? 通常可以在代码中限制递归调用的最大深度的方式来解决这个问题。比如Python语言,限制了递归深度,当递归深度过高,则会抛出:RecursionError: maximum recursion depth exceeded in comparison异常,防止系统性崩溃。 我们在代码中也可以自己设置递归的深度,比如限制n最大不能超过100,代码如下: def walk(n): if n == 1: return 1 if n == 2: return 2 if n > 100: raise RecursionError("recursion depth exceede 100") return walk(n - 1) + walk(n - 2) 除此之外,使用递归时还会出现重复计算的问题。什么意思?拿走台阶那个例子来说明。比如计算6个台阶的走法f(6),过程如下图: 从图中,我们可以直观地看到,想要计算 f(5),需要先计算 f(4) 和 f(3),而计算 f(4) 还需要计算 f(3),因此,f(3) 就被计算了很多次,这就是重复计算问题。 那么怎么解决这个问题?为了避免重复计算,我们可以通过字典保存已经求解过的 f(k)。当递归调用到 f(k) 时,先看下是否已经求解过了。如果是,则直接从字典中取值,不需要重复计算,这样就能避免刚讲的问题了。 修改下计算台阶走法的代码,解决重复计算的问题: data = dict() # 保存中间结果def walk(n): if n == 1: return 1 if n == 2: return 2 if n > 100: raise RecursionError("recursion depth exceed 100") if n in data: # 如果在中间结果中,则直接返回,不用进入递推公式再次计算 return data[n] result = walk(n - 1) + walk(n - 2) # 在递归公式前面增加个查找步骤 data[n] = result # 将计算结果保存在中间结果data字典中 return resultprint(walk(6)) 本文分享自微信公众号 - 明说软件测试(liuchunmingnet)。如有侵权,请联系 support@oschina.cn 删除。本文参与“OSC源创计划”,欢迎正在阅读的你也加入,一起分享。

资源下载

更多资源
Mario

Mario

马里奥是站在游戏界顶峰的超人气多面角色。马里奥靠吃蘑菇成长,特征是大鼻子、头戴帽子、身穿背带裤,还留着胡子。与他的双胞胎兄弟路易基一起,长年担任任天堂的招牌角色。

Nacos

Nacos

Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service 的首字母简称,一个易于构建 AI Agent 应用的动态服务发现、配置管理和AI智能体管理平台。Nacos 致力于帮助您发现、配置和管理微服务及AI智能体应用。Nacos 提供了一组简单易用的特性集,帮助您快速实现动态服务发现、服务配置、服务元数据、流量管理。Nacos 帮助您更敏捷和容易地构建、交付和管理微服务平台。

Sublime Text

Sublime Text

Sublime Text具有漂亮的用户界面和强大的功能,例如代码缩略图,Python的插件,代码段等。还可自定义键绑定,菜单和工具栏。Sublime Text 的主要功能包括:拼写检查,书签,完整的 Python API , Goto 功能,即时项目切换,多选择,多窗口等等。Sublime Text 是一个跨平台的编辑器,同时支持Windows、Linux、Mac OS X等操作系统。

WebStorm

WebStorm

WebStorm 是jetbrains公司旗下一款JavaScript 开发工具。目前已经被广大中国JS开发者誉为“Web前端开发神器”、“最强大的HTML5编辑器”、“最智能的JavaScript IDE”等。与IntelliJ IDEA同源,继承了IntelliJ IDEA强大的JS部分的功能。

用户登录
用户注册