1、手机自动化测试的原理为PC上一个控制端(
测试工具)与手机上的一个agent端,通过串口、USB或者无线方式将PC与手机终端相连,然后应用测试工具向手机发送请求或者命令,手机收到命令或者请求后,交给agent端解析,然后agent将这些解析的命令下发给手机的各个功能模块所能识别的命令,调用那些功能模块模拟操作。完成这些操作后,手机会返回一些信息,agent可以抓取这些信息,然后传回给PC端,这样就完成了一个完整的手机自动化测试。
2、关键点在于agent,有的公司是向自己的手机终端的软件功能模块中植入测试程序响应代码,有的公司可以利用MMI_Command的方式来控制手机终端;原理就是给手机提供一个响应的接口。
3、而对于PC控制端,这个测试脚本用各种编程语言都可以,看如何定义
4、而又的自动化测试设计成录制的机制,说通俗点,就是记录手工操作的键盘信息或者LCD的操作信息(LCD需要用到智能识别机制)
5、自动化测试框架的搭建方法是通用的,你需要有一套自己的测试框架才能保证自动化测试的顺利开展。
1、CTS,CTS 测试基于Android instrumentation 测试, 其又基于
JUnit 测试。说白了, CTS 就是一堆
单元测试用例。这也是Java 语言的擅长部分。
2、 Monkey工具,Monkey是Android中的一个命令行工具,可以运行在模拟器里或实际设备中。它向系统发送伪随机的用户事件流(如按键输入、触摸屏输入、手势输入等),实现对正在开发的应用程序进行
压力测试。Monkey测试是一种为了测试软件的稳定性、健壮性的快速有效的方法。
3、ASE,ASE 意思为Android 脚本环境, 即我们可以通过脚本(比如
Python)调用Android 的功能,从而定制一些测试。比如打电话,发短信,浏览网页,等。我们可以扩充它的API(Java 部分), 并用python 脚本调用这些API, 从而实现丰富的测试功能。用于API 部分可以访问到Android 全部API, python 又能灵活部署测试,所以ASE 的扩展性非常好。
4、Robotium,该工具用于黑盒的自动化测试。可以在有源码或者只有APK 的情况下对目标应用进行测试。Robotimu 提供了模仿用户操作行为的API,比如在某个控件上点击,输入Text等等。(推举你可以研究一下这个工具,开源的,我有资料)
5、可以自己开发一个手机方面的自动化测试工具,原理上一样
Python’s standard urllib2 module provides most of the HTTP capabilities you need, but the API is thoroughly broken. It was built for a different time — and a different
web. It requires an enormous amount of work (even method overrides) to perform the simplest of tasks.
Things shouldn’t be this way. Not in Python.
是的,Python的urllib2不应该是这样,当我们试图让http库更加优雅的时候,我们找到了Requests,有一种相见恨晚的感觉。
今天推荐Requests给各位
测试人也是有原因的,我们在
工作中难免会碰到一些奇葩的
性能测试需求,例如测试某个中间件的消息处理效率等,当然,如果你熟悉JAVA,他应该也是有一个类似的库的。那么如果你是一个Pythoner,Requests无疑是你的第一选择,我们来看一下它优雅的DEMO:
>>> r = requests.get('https://api.github.com/user', auth=('user', 'pass')) >>> r.status_code 200 >>> r.headers['content-type'] 'application/json; charset=utf8' >>> r.encoding 'utf-8' >>> r.text u'{"type":"User"...' >>> r.json() {u'private_gists': 419, u'total_private_repos': 77, ...} |
Requests提供了最简便的JSON解析方法,类似于这样:
>>> import requests >>> r = requests.get('https://github.com/timeline.json') >>> r.json() [{u'repository': {u'open_issues': 0, u'url': 'https://github.com/... |
一个自定义header的例子,POST
>>> import json >>> url = 'https://api.github.com/some/endpoint' >>> payload = {'some': 'data'} >>> headers = {'content-type': 'application/json'} >>> r = requests.post(url, data=json.dumps(payload), headers=headers) |
看到这里,各位Pythoner估计已经按捺不住激动的
心情。
在这里,你可以欣赏到更多API和EG。
今天因为
工作需要,把以前编写的一个GPS测试程序拿出来重新修改了一下。这个程序说起来有些历史了,是我11年编写的,那时候学了
Android开发没多久,算是一个实验性的作品。现在工作需要,重新拿出来修整。同时发现我对android的GPS服务了解并不深,所以今天特意阅读了有关GPS服务的一些资料,把相关知识点记录下来。
本人做了GPS相关的嵌入式软件已经几年了,所以说起要做个测试GPS定位模块的程序,第一反应就是串口读取GPS模块的数据,然后解析GPS的NMEA格式数据。NMEA是一种标准化数据格式,不仅仅GPS上应用了,其他一些工业通信也是使用这种标准化数据格式。解析相关数据然后显示出来,就完成了一个基本的GPS定位
测试功能。
查了一下才发现Android上做GPS相关定位服务,不需要读取NMEA数据分析,Android已经封装好了相关服务,你要做的就是调用API。这个不知道应该觉得爽还是觉得纠结。(Android也提供了读取NMEA接口,下面会说到)
1、Android 定位服务
下面我们先来看看Android有关定位服务提供的支持:
Android定位服务都是位于location下,上面都有相关说明,这里就不详细解析。有一点有需要说说的
是:GpsStatus.NmeaListener 官方的说法是可以读取NMEA数据,但是我这里测试发现,并没有读取到NMEA的数据。查阅过一些资料,说是google在底层并没有实现数据反馈的功能。有时间,需要查看一下源码。
2、LocationManager定位
//Edited by mythou //http://www.cnblogs.com/mythou/ //获取定位服务 LocationManager locationManager = (LocationManager) this.getSystemService(Context.LOCATION_SERVICE); //判断是否已经打开GPS模块 if (locationManager.isProviderEnabled(android.location.LocationManager.GPS_PROVIDER)) { //GPS模块打开,可以定位操作 } // 通过GPS定位 String LocateType= locationManager.GPS_PROVIDER; Location location = locationManager.getLastKnownLocation(LocateType); // 设置监听器,设置自动更新间隔这里设置1000ms, 移动距离:0米。 locationManager.requestLocationUpdates(provider, 1000, 0, locationListener); // 设置状态监听回调函数。statusListener是监听的回调函数。 locationManager.addGpsStatusListener(statusListener); //另外给出 通过network定位设置 String LocateType= locationManager.NETWORK_PROVIDER; Location location = locationManager.getLastKnownLocation(LocateType); |
3、GpsStatus监听器
上面给出了定位服务的初始化设置步骤,但我们都知道GPS卫星是定期广播数据的,也就是说会定期收到卫星的GPS数据。我们并不能跟卫星主动申请数据,只能被动接收数据。(中国的北斗2倒是可以发送卫星报文给卫星)因此我们需要注册一个监听器来处理卫星返回的数据。
//Edited by mythou //http://www.cnblogs.com/mythou/ private final GpsStatus.Listener statusListener = new GpsStatus.Listener() { public void onGpsStatusChanged(int event) { // GPS状态变化时的回调,获取当前状态 GpsStatus status = locationManager.getGpsStatus(null); //自己编写的方法,获取卫星状态相关数据 GetGPSStatus(event, status); } }; |
4、获取搜索到的卫星
//Edited by mythou //http://www.cnblogs.com/mythou/ private void GetGPSStatus(int event, GpsStatus status) { Log.d(TAG, "enter the updateGpsStatus()"); if (status == null) { } else if (event == GpsStatus.GPS_EVENT_SATELLITE_STATUS) { //获取最大的卫星数(这个只是一个预设值) int maxSatellites = status.getMaxSatellites(); Iterator<GpsSatellite> it = status.getSatellites().iterator(); numSatelliteList.clear(); //记录实际的卫星数目 int count = 0; while (it.hasNext() && count <= maxSatellites) { //保存卫星的数据到一个队列,用于刷新界面 GpsSatellite s = it.next(); numSatelliteList.add(s); count++; Log.d(TAG, "updateGpsStatus----count="+count); } mSatelliteNum = numSatelliteList.size(); } else if(event==GpsStatus.GPS_EVENT_STARTED) { //定位启动 } else if(event==GpsStatus.GPS_EVENT_STOPPED) { //定位结束 } } |
上面就是从状态值里面获取搜索到的卫星数目,主要是通过status.getSatellites()实现。获取到的GpsSatellite对象,
保存到一个队列里面,用于后面刷新界面。上面是获取GPS状态监听器,除了GPS状态外,我们还需要监听一个服务,
就是:LocationListener,定位监听器,监听位置的变化。这个对做定位服务的应用来说,十分重要。
5、LocationListener监听器
//Edited by mythou //http://www.cnblogs.com/mythou/ private final LocationListener locationListener = new LocationListener() { public void onLocationChanged(Location location) { //当坐标改变时触发此函数,如果Provider传进相同的坐标,它就不会被触发 updateToNewLocation(location); Log.d(TAG, "LocationListener onLocationChanged"); } public void onProviderDisabled(String provider) { //Provider被disable时触发此函数,比如GPS被关闭 Log.d(TAG, "LocationListener onProviderDisabled"); } public void onProviderEnabled(String provider) { // Provider被enable时触发此函数,比如GPS被打开 Log.d(TAG, "LocationListener onProviderEnabled"); } public void onStatusChanged(String provider, int status, Bundle extras) { Log.d(TAG, "LocationListener onStatusChanged"); // Provider的转态在可用、暂时不可用和无服务三个状态直接切换时触发此函数 if (status == LocationProvider.OUT_OF_SERVICE || status == LocationProvider.TEMPORARILY_UNAVAILABLE) { } } }; |
位置监听回调是用来处理GPS位置发生变化的时候,自动回调的方法,我们可以从这里获取到当前的GPS数据。另外我们可以通过回调函数提供的location参数,获取GPS的地理位置信息,包括经纬度、速度、海拔等信息。 6、获取地理位置信息(经纬度、卫星数目、海拔、定位状态)
//Edited by mythou //http://www.cnblogs.com/mythou/ //location对象是从上面定位服务回调函数的参数获取。 mLatitude = location.getLatitude(); // 经度 mLongitude = location.getLongitude(); // 纬度 mAltitude = location.getAltitude(); //海拔 mSpeed = location.getSpeed(); //速度 mBearing = location.getBearing(); //方向 |
7、获取指定卫星信息(方向角、高度角、信噪比)
//Edited by mythou //http://www.cnblogs.com/mythou/ //temgGpsSatellite就是我们上面保存的搜索到的卫星 //方向角 float azimuth = temgGpsSatellite.getAzimuth(); //高度角 float elevation = temgGpsSatellite.getElevation(); //信噪比 float snr = temgGpsSatellite.getSnr(); |
利用方向角、高度角我们可以绘画出一个二维图形,表示卫星在地球哪个方位,信噪比作用更大。一般的卫星定位测试软件,都提供了信噪比的状态图,这是表示GPS模块搜星能力的代表。
8、绘画二维卫星位置图
下面是我做的GPS测试的效果图:
下面给出一个根据方向角和高度角,计算卫星二维图里面位置的方法,上面效果图左边的绿色圆点就代表卫星位置。
右边的信噪比柱状图,代表卫星的接收信号能力。
//Edited by mythou //http://www.cnblogs.com/mythou/ //根据方向角和高度角计算出,卫星显示的位置 Point point = new Point(); int x = mEarthHeartX; //左边地球圆形的圆心位置X坐标 int y = mEarthHeartY; //左边地球圆形的圆心位置Y坐标 int r = mEarthR; x+=(int)((r*elevation*Math.sin(Math.PI*azimuth/180)/90)); y-=(int)((r*elevation*Math.cos(Math.PI*azimuth/180)/90)); point.x = x; point.y = y; //point就是你需要绘画卫星图的起始坐标 |
信噪比的绘画,就是一个单位换算,这里就不给代码了。
9、总结:
Android为我们提供了很方便的位置服务,主要通过GpsStatus、LocationManager、GpsSatellite这几个类实现相关服务和监听。
不过个人觉得如果能直接读取NMEA的数据也是很方便,起码对于某些应用来说,可以获取更多信息。
信息如水 压力如潮
功能实现阶段,我们对得要处理的信息分析得很细致,很透彻,所谓细如丝,透如水。然而,到了产品的阶段,要处理的信息却如同潮洪而至,原本的假设预想,通通被击成了碎片。这时候产生的错误和问题,很难在开发机上重现。
如果说用户验收
测试是对功能实现的检查,需要滴水不漏;
压力测试则是容量的考验,迎接浪的洗礼。
环肥燕瘦
压力测试的工具颇多,尤其是HP的
LoadRunner甚至成为了行业标准。可是,在研究和考察的过程中,心里却慢慢有了质疑,我是否非得用这些工具吗? 一则,它们是商业软件,价格不菲;二则,还是因为是商业软件,功能太多,太庞大,很多东西我都不需要。为什么不自己做一个简单实用的呢?
在小赵研究
Selenium时,我觉得用他用的语法很贴近业务语言,于是我提出一个问题,可以用于压力测试吗?他说不行,因为Selenium是要完全启动浏览器。平时,看起来瘦小的浏览器,其实很耗资源,特别是与压力测试的容量来比,浏览器是个不折不扣的大胖子。你可以试一下,在你的机器上同时开启100个浏览窗口,会是个什么状况。
苗条美人 HttpClient
否定了Selenium之后,很快就找到了我的目标HttpClient (其实还有个前生WebClient,后面有叙)。从名称,我们就可以知道,它已经定位到很低Http层,这一层是效率与易用的一个最佳平衡点。但是,它是.Net 4.5下的部件,在.Net 4.0必须用NuGet来下载。
查看了很多资料以后,我可以确信,HttpClient正是我想要的。她还有一个很大的特色,完全只提供异步接口。这实际上是另一种大瘦身,耗用资源上的瘦身,HttpClient正式我要的窈窕淑女。
前生:WebClient
var values = new NameValueCollection(); foreach (var key_value in ui.FormData) { values.Add(key_value.Key, key_value.Value); } var client = new WebClient(); client.Headers.Add("Content-Type", "application/x-www-form-urlencoded"); Console.WriteLine(string.Concat(base_site + ui.Path, ui.Method.ToString().ToLower(), values)); byte[] result = client.UploadValues(base_site + ui.Path, ui.Method.ToString().ToLower(), values); string ResultAuthTicket = Encoding.UTF8.GetString(result); Console.WriteLine(client.BaseAddress); Console.WriteLine(client.ResponseHeaders.ToString()); Console.WriteLine(ResultAuthTicket); |
HttpClient的Async方法,注意最后的Wait()有把异步转化为了同步
var form_data=new Dictionary<string, string>(); form_data.Add("system_account","test1@skight.com"); form_data.Add("system_password","123456"); var values = new NameValueCollection(); foreach (var key_value in form_data) { values.Add(key_value.Key, key_value.Value); } var client = new HttpClient(); client.GetStringAsync("http://esr20syst.skight.com/District/03/UserLogin.do") .ContinueWith( t => { Console.WriteLine("Time {0}", DateTime.Now); Console.WriteLine(t.Result); }) .Wait(); |
Sync 还是Async 这,是一个问题
.Net 4,5 出来之后,一直没有对它的新功能和特性太在意。只是公司升级使用VS2012,除了灰不溜秋的界面,而所谓的性能提高(其实,是VS2010太次)之外,也没有特别感觉。
然而,这次在查看HttpClient资料时,却意外发现了.Net 4.5 语法级别的一个亮点: Asyn和Await。这让异步编程更简便,更漂亮。看来,今后异步编程是一个大潮流,微软也不惜余力。
新语法应用之后的效果,似乎和平时的同步编码没有太大区别,除了不时冒出来的Await和Async
var form_data=new Dictionary<string, string>(); form_data.Add("system_account","test1@skight.com"); form_data.Add("system_password","123456"); foreach (var key_value in form_data) { values.Add(key_value.Key, key_value.Value); } var httpClient = new HttpClient(); var content= await httpClient.GetStringAsync("http://esr20syst.skight.com/District/03/UserLogin.do"); Console.WriteLine(t.Result); |
异步性能的福利是不可随小觑的。之前,有Node.js构建的的Web服务比Apache快很多(http://zgadzaj.com/benchmarking-nodejs-basic-performance-tests-against-apache-php)就是得益于Javascript天生的函数回调方式支持的异步运行。现在有.Net对Async的友好支持,以及大量组件基于异步方式的重写。据说,微软推荐,凡是运行时间超过20毫秒的功能,就要用异步方式来写。HttpClient就是一个例子,它的前身WebClient就不具异步调用,而HttpClient干脆就不提供同步接口。
平行宇宙 Parallel
其实,无论是的Async还是Parallel,都是语法糖,可是作为辛苦的开发者,我们好的就是这一口。
Async让我们发出网络请不必再等待,Parallel让我们很容易的持续发出平行请求,这就是一个完全的压力测试模型了。我这里简单设置了一个100 * 10 个请求。没有具体计算,共发出多少个请求,我只知道,多得已经足够让我的系统重现产品机上的问题了。
Parallel.For(1, 1000, i => Parallel.For(1, 5, case_number => LoginScenario(case_number) .run_by(runner) )); |
附:我的业务语法糖DSL
这里是我对系统页面操作的定义代码,用语法糖DSL的方式实现,一定程度上实现了需求即代码即文档的要求吧。这部分代码不能直接运行,因为它使用了我自己的Web框架,从而可以用强类型自动生成URL。这里提供出来只是作参考,作为示例的一部分。
private static Scenario LoginScenario(int case_number) { return UI.context(Keys.Context.District.with_value(DistrictIdentifier.of("03"))) .to<UserLoginGet>() .then( UI.input(SystemPayloadKeys.Account.with_value(string.Format("test{0}@skight.com", case_number))) .and_input(SystemPayloadKeys.Password.with_value("123456")) .to<UserLoginPost>()); } |
我们在运行
QTP批处理时,不需要把QTP的主界面显示出来,以免它阻碍了你的操作视线,那下面介绍二个函数方便你的QTP在运行过程中“收入自如”:
'让QTP运行时保持最小化
Public Sub QTP_Small() Dim objQTPWin Set objQTPWin = GetObject("" , "QuickTest.Application") objQTPWin.WindowState = "Minimized" Set objQTPWin = Nothing End Sub |
'恢复QTP窗口
Public Sub QTP_Big() Dim objQTPWin Set objQTPWin = GetObject("" , "QuickTest.Application") objQTPWin.WindowState = "Restored" Set objQTPWin = Nothing End Sub |
计划名CADCSC软件质量保证计划
项目名中国控制系统CAD工程化软件系统
项目委托单位
代表签名年月日
项目承办单位
代表签名年月日
1引言
1.1目的
本计划的目的在于对所开发的CADCSC软件规定各种必要的质量保证措施,以保证所交付的CADCSC软件能够满足项目委托书或合同中规定的各项需求,能够满足本项目总体组制定的且经领导小组批准的该软件系统需求规格说明书中规定的各项具体需求。
软件开发单位在开发CADCSC软件系统所属的各个子系统(其中包括为本项目研制或选用的各种支持软件)时,都应该执行本计划中的有关规定,但可根据各自的情况对本计划作适当的剪裁,以满足特定的质量保证要求,剪裁后的计划必须经总体组批准。
1.2定义本计划用到的一些术语的定义按GB/T11457和GB/T12505.1.3参考资料GB/T11457软件工程术语GB8566计算机软件开发规范GB8567计算机软件产品开发文件编制指南GB/T12504计算机软件质量保证计划规范GB/T12505计算机软件
配置管理计划规范CADCSC软件配置管理计划
2管理
2.1机构在本软件系统整个开发期间,必须成立软件质量保证小组负责质量保证
工作。软件质量保证小组属总体组领导,由总体组代表、项目的软件工程小组代表、项目的专职质量保证人员、项目的专职配置管理人员以及各个子系统软件质量保证人员等方面的人员组成,由项目的软件工程小组代表任组长。各子系统的软件质量保证人员在业务上受软件质量保证小组领导,在行政上受各子系统负责人领导。
软件质量保证小组和软件质量保证人员必须检查和督促本计划的实施。各子系统的软件质量保证人员有权直接向软件质量保证小组报告子项目的软件质量状况。各子系统的软件质量保证人员应该根据对子项目的具体要求,制订必要的规程和规定,以确保完全遵守本计划的所有要求。
2.2任务软件质量保证工作涉及软件生存周期各阶段的活动,应该贯彻到日常的软件开发活动中,而且应该特别注意软件质量的早期评审工作。因此,对新开发的或正在开发的各子系统,要按照GB8566与本计划的各项规定进行各项评审工作。软件质量保证小组要派成员参加所有的评审与检查活动。评审与检查的目的是为了确保在软件开发工作的各个阶段和各个方面都认真采取各项措施来保证与提高软件的质量。在CADCSC软件开发过程中,经总体组研究决定,要进行如下几类评审与检查工作:a.阶段评审:在软件开发过程中,要定期地或阶段性地对某一开发阶段或某几个开发阶段的阶段产品进行评审。根据总体组研究决定,在CADCSC软件及其所属各子系统的开发过程中,应该进行以下三次评审:第一次评审软件需求、概要设计、验证与确认方法;第二次评审详细设计、
功能测试与演示,并对第一次评审结果复核;第三次是功能检查、物理检查和综合检查。关于这些评审工作的详细内容见第5章。
阶段评审工作要组织专门的评审小组,原则上由项目总体小组成员或特邀专家担任评审组长,评审小组成员应该包括项目委托单位或用户的代表、质量保证人员、软件开发单位和上级主管部门的代表,其他参加人员视评审内容而定。
每一次评审工作都应填写评审总结报告(RSR)、评审问题记录(RPL)、评审成员签字表(RMT)与软件问题报告单(SPR)等四张表格。这四张阶段评审报表的具体格式应与附录C中的规定相一致。
b.日常检查:在CADCSC软件的工程化生产过程中,各子系统应该填写项目进展报表,即软件进展报表表头、软件阶段进度表、软件阶段产品完成情况表、软件开发费用表等四张表格。项目总体组杨以通过项目进展季报表发现有关软件质量的问题。项目进展季报表的具体格式应与附录B中的规定相一致。
c.软件验收:必须组织专门的验收小组对CADCSC软件系统及其所属各个子系统进行验收。验收工作应按照经项目委托单位“国家自然科学基金委员会信息科学部”与CADCSC总体组双方都认可的验收规程正式履行验收手续。验收内容应包括文档验收、程序验收、演示、验收测试与测试结果评审等几项工作。具体的验收规程另行制订。
2.3职责在CADCSC项目的软件质量保证小组中,其各方面人员的职责如下:a.组长全面负责有关软件质量保证的各项工作;b.总体组代表负责有关阶段评审、项目进展报表检查以及软件验收准备等三方面工作中的质量保证工作;c.项目的专职配置管理人员负责有关软件配置变动、软件媒体控制以及对供货单位的控制等三方面的质量保证活动;d.各子系统的软件质量保证人员负责测试复查和文档的规范化检查工作;e.用户代表负责反映用户的质量要求,并协助检查各类人员对软件质量保证计划的执行情况;f.项目的专职质量保证人员协助组长开展各项软件质量保证活动,负责审查所采用的质量保证工具、技术和方法,并负责汇总、维护和保存有关软件质量保证活动的各项记录。
3文档
本章给出了在CADCSC软件开发过程各阶段需要编制的文档名称及其要求,并且规定了评审文质量的通用的度量准则。
3.1.基本文档为了确保软件的实现满足项目委托单位“国家自然科学基金委员会信息科学部”认可的需求规格说明书中规定的各项需求,CADCSC软件各开发单位至少应该编写以下八个方面内容的文档:a.软件需求规格说明书(SRS);b.软件设计说明书(SDD),对一些规模较大或复杂性较高的项目,应该把本文档分成概要设计说明书(PDD)与详细设计说明书(DDD)两个文档;c.软件测试计划(STP);d.软件测试报告(STR);e.用户手册(SUM);f.源程序清单(SCL);g.项目实施计划(PIP);h.项目开发总结(PDS)。
3.2其他文档除了基本文档之外,对于尚在开发中的软件,还应该包括以下四个方面的文档:a.软件质量保证计划(SQAP);b.软件配置管理计划(SCMP);c.项目进展报表(PPR);d.阶段评审报表(PRR)。
注:前面两个文档由项目软件工程小组制订,属于管理文档,各个子系统的项目承办单位与软件开发单位都应充分考虑执行计划中规定的条款。后面两类文档属于工作文档,就是本计划的2.2中提到的四张阶段评审表与四张项目进展季报表,各个子系统的项目承办单位或软件开发单位应该按照规定要求认真填写有关内容。
3.3文档质量的度量准则文档是软件的重要组成部分,是软件生存周期各个不同阶段的产品描述。验证和确认就是要检查各阶段文档的合适性。评审文档质量的度量准则有以下六条:a.完备性:所有承担软件开发任务的单位,都必须按照GB8567的规定编制相应的文档,以保证在开发阶段结束时其文档是齐全的。
b.正确性:在软件开发各个阶段所编写的文档的内容,必须真实地反映该阶段的工作且与该阶段的需求相一致。
c.简明性:在软件开发各个阶段所编写的各种文档的语言表达应该清晰、准确简练,适合各种文档的特定读者。
d.可追踪性:在软件开发各个阶段所编写的各种文档应该具有良好的可追踪性。文档的可追踪性包括纵向可追踪性与横向可追踪性两个方面。前者是指在不同文档的相关内容之间相互检索的难易程度;后者是指确定同一文档某一内容在本文档中的涉及范围的难易程度。
e.自说明性:在软件开发各个阶段所编写的各种文档应该具有较好的自说明性。文档的自说明性是指在软件开发各个阶段中的不同文档能独立表达该软件其相应阶段的阶段产品的能力。
f.规范性:在软件开发各个阶段所编写的各种文档应该具有良好的规范性。文档的规范性是指文档的封面、大纲、术语的含义以及图示符号等符合有关规范的规定。
4标准、条例和约定在CADCSC工程化软件系统的开发过程中,还必须遵守下列标准、条例和约定:a.《CADCSC软件配置管理计划》,CADCSC软件工程小组编,1988年。
b.《C语言编程格式约定》,CADCSC软件工程小组编,1988年。
5评审和检查
本章具体规定了应该进行的阶段评审、阶段评审的内容和评审时间要求。对新开发的或正在开发的各个子系统,都要按照GB8566的规定认真进行定期的或阶段性的各项评审工作。就整个软件开发过程而言,至少要进行软件需求评审、概要设计评审、详细设计评审、软件验证和确认评审、功能检查、物理检查、综合检查以及管理评审等八个方面的评审和检查工作。如本计划第2.2条所述,经总体组研究决定,在CADCSC软件及其所属各个子系统的开发过程中,把前七种评审分成三次进行。在每次评审之后,要对评审结果作出明确的管理决策。下面给出每次评审应该进行的工作。
5.1第一次评审第一次评审会对软件需求、概要设计以及验证与确认方法进行评审。
a.软件需求评审(SRR)应确保在软件需求规格说明书中规定的各项需求的合理性。
b.概要设计评审(PDR)应评价软件设计说明书中的软件概要设计的技术合适性。
c.软件验证和确认评审(SV&VR)应评价软件验证和确认计划中确定的验证和确认方法的合适性与完整性。
5.2第二次评审第二次评审会要对详细设计、功能测试与演示进行评审,并对第一次评审结果进行复核。如果在软件开发过程中发现需要修改第一次评审结果,则应按照《CADCSC软件配置管理计划》的规定处理。
a.详细设计评审(DDR)应确定软件设计说明书中的详细设计在满足软件需求规格说明书中的需求方面的可接受性。
b.编程格式评审应确保所有编码采用规定的工作语言,能在规定的运行环境中运行,满足《C语言编程格式约定》,并且符合GB8566中提倡的编程风格。在满足这些要求之后,方可进行测试工作评审。
c.测试工作评审应对所有的程序单元进行静态分析,检查其程序结构(即模块和函数的调用关系和调用序列)和变量使用是否正确。在通过静态分析后,再进行结构测试和功能测试。在结构测试中,所有程序单元结构测试的语句覆盖率Co必须等于100%,分支覆盖率C1必须大于或等于85%.要给出每个单元的输入和输出变量的变化范围。各个子系统只进行功能测试,不单独进行结构测试,因而要登录程序单元之间接口的变量值,力图使满足单元测试的C1和Co准则的那此测试用例在子系统功能测试时得到再现。测试工作评审要检查所进行的测试工作是否满足这些要求。特别在评审功能测试工作时,不仅要运行变量的等价值,而且要运行变量的(合法的和非法的)边界值;不仅要运行开发单位给出的测试用例,而且要允许运行任务委托单位或用户、评审人员选定的采样用例。
5.3第三次评审第三次评审会要进行功能检查、物理检查和综合检查。这些评审会应在集成测试阶段结束后进行。
a.功能检查(FA)应验证所开发的软件已经满足在软件需求规格说明书中规定的所有需求。
b.物理检查(PA)应对软件进行物理检查,以验证程序和文档已经一致、并已做好了交付的准备。
c.综合检查(CA)应验证代码和设计文档的一致性、接口规格说明之间的一致性(硬件和软件)、设计实现和功能需求的一致性、功能需求和测试描述的一致性。
6软件配置管理
对CADCSC工程化软件系统的各项配置进行及时、合理的管理,是确保软件质量的重要手段,也是确保该软件具有强大生命力的重要措施。有关CADCSC工程化软件的配置管理工作,可按CADCSC软件工程小组编写的《CADCSC软件配置管理计划》。在软件配置管理工作中,要特别注意规定对软件问题报告、追踪和解决的步骤,并指出实现报告、追踪和解决软件问题的机构及其职责。
7工具、技术和方法
在CADCSC项目所属的各个子系统(其中包括有关的支持软件)的研制与开发过程中,都应该在各自的软件质量保证活动中合理地使用软件质量活动的支持工具、技术和方法。这些工具主要有下列三种:a.C软件测试工具。它支持用C语言编写的模块的静态分析、结构测试与功能测试。主要功能为:协助测试人员判断程序结构与变量使用情况是否有错;给测试人员提供模块语句覆盖率Co和分支覆盖率C1的值,并显示未覆盖语句和未覆盖分支的号码及其分支谓词,给出不同测试用例有效性的表格;同时提出功能测试的有效情况,并协助组织最终交付给用户的有效测试用例的集合。
b.软件配置管理工具。它支持用户对源代码清单的更新管理以及对重新编译与连接的代码的自动组织;支持用户在不同文档相关内容之间进行相互检索并确定同一文档某一内容在本文档中的涉及范围;同时还应支持软件配置管理小组对软件配置更改进行科学的管理。
c.文档辅助生成工具与图形编辑工具。它主要协助用户绘制描述程序流程与结构的DFD图与SC图、绘制描述软件功能(输入、输出关系)的曲线以及绘制描述控制系统特性的一些其他图形,同时还可生成若干与CADCSC软件文档编制大纲相适应的文档模块板。用户利用这个工具的正文与图形编辑功能以及上述辅助功能,可以比较方便地产生清晰悦目的文档,也有利于对文档进行更改,还有助于提高文档的编制质量。
8媒体控制
为了保护计算机程序的物理媒体,以免非法存取、意外损坏或自然老化,CADCSC工程化软件系统的各个子系统(包括支持软件)都必须设立软件配置管理人员,并按照CADCSC软件工程小组制订的、且经CADCSC总体组批准的《CADCSC软件配置管理计划》妥善管理和存放各个子系统及其专用支持软件的媒体。
9对供货单位的控制
CADCSC项目所属的各个子系统开发组,如果需要从软件销售单位购买、委托其他开发单位开发、从开发单位现存软件库中选用或从项目委托单位或用户的现有软件库中选用软部件时,则在选用前应向CADCSC总体组报告,然后由CADCSC总体组组织“软件选用评审小组”进行评审、测试与检查,只有当演示成功、测试合格后才能批准选用。如果只选用其中部分内容,则按待开发软件的处理过程办理,此时CADCSC总体组不作干预。
10记录收集、维护和保存
在CADCSC项目及其所属的各个子系统的研制与开发期间,要进行各种软件质量保证活动,准确记录、及时分析并妥善保存有关这些活动的记录,是确保软件质量的重要条件。在软件质量保证小组中,应有专人负责收集、汇总与保存有关软件质量保证活动的记录。要收集、汇总与保存的记录名字及其保存期限见表1.表1记录名称及其保存的期限附录B项目进展报表(参考件)
B1项目进展报表(月报表或季报表)由一个项目进展报表表头(表B1)和另外三个表格(表B2、表B3、表B4)组成。在表B2“软件阶段进度表中”中,要填写各个阶段的开工日期与结束日期。其中计划进度是指在项目实施计划中确定的计划进度,因此可以由管理人员事先填好,而不必由开发人员填写。实际进度是指该项目实际的开工日期与结束日期,它将随着该项目的不断进展填写。其中调整进度是指项目组长发现实际进度与计划进度不符时提出的进度修改建议;但经项目管理人员研究后,可能对此修改建议作某些更改。此外,在相继的若干次报表中,项目组长提出的建议修改日期也可能是不相同的。在此我们规定,最终的调整进度由项目经理来确定。在表B3“软件阶段产品完成情况表”中,要填写各个文档的开始编写日期与完成日期。其中关于对计划进度、调整进度与实际进度的含义的解释与上相同。表B4是关于统计软件开发费用的表格。
表B1项目进展报表表头
注:SA&SD(systemanalysis&softwaredefinitionphase):系统分析与软件定义阶段。
——RA(requirementsanalysisphase):需求分析阶段。
——PD(preliminarydesignphase):概要设计阶段。
——DD(detaileddesignphase):详细设计阶段。
——CD&UT(coding&unittestingphase):编码与单元测试阶段。
——IT&ST(integrating&systemtestingphase):组装与系统测试阶段
——IS&AC(installation&acceptancephase):安装与验收阶段。
——TSSD(totalsoftwaresystemdevelopmentphase):整个软件系统的开发阶段。
附录C项目阶段评审表(参考件)
//统计某个字符出现的次数
private void countSubString(){
String string1="香蕉、玉米、面粉";
String string2="香蕉、玉米、面粉";
String string3="牛奶、鸡蛋";
StringBuffer stringBuffer=new StringBuffer();
stringBuffer.append(string1).append("、").append(string2).append("、").append(string3).append("、");
String totalString=stringBuffer.toString();
System.out.println("组拼后的字符串为:"+totalString);
while (totalString.length()>0) {
//得到第一个字符串比如"香蕉、"
int index=totalString.indexOf("、");
String foodName=totalString.substring(0,index+1);
Pattern pattern = Pattern.compile(foodName);
Matcher matcher = pattern.matcher(totalString);
int count=0;
while(matcher.find()){
count++;
}
totalString= totalString.replaceAll(foodName, "");
System.out.println("食品名字为:"+foodName+",出现次数为:"+count);
System.out.println("统计删除后字符串为:totalString="+totalString);
System.out.println("===============================");
}
set linesize 120 pagesize 66 col c1 for a9 col c1 heading "OS User" col c2 for a9 col b1 for a9 col b1 heading "Unix PID" col b2 for 9999 justify left col b2 heading "SID" col b3 for 99999 justify left col b3 heading "SERIAL#" col sql_text for a35 col event for a30 break on b1 nodup on c1 nodup on c2 nodup on b2 nodup on b3 skip 3 select c.spid b1, b.osuser c1, b.username c2, b.sid b2, b.serial# b3, b.event, a.sql_text from v$sqltext a, v$session b, v$process c where a.address = b.sql_address -- and b.status = 'ACTIVE' /* YOU CAN CHOOSE THIS OPTION ONLY TO SEE -- ACTVE TRANSACTION ON THAT MOMENT */ and b.paddr = c.addr and a.hash_value = b.sql_hash_value order by c.spid, a.hash_value, a.piece / REM TOP SESSION with sessions as (select /*+ materialize */ sess.inst_id, sess.sid, sess.serial#, sess.username, sess.module, sess.program, stat.value cpu_used_by_this_session, i.physical_reads, i.block_gets, sess.command, sess.status, sess.lockwait, decode(sess.sql_hash_value, 0, sess.prev_hash_value, sess.sql_hash_value) sql_hash_value, decode(sess.sql_address, '00', sess.prev_sql_addr, sess.sql_address) sql_address from gv$sesstat stat, gv$session sess, gv$sess_io i where stat.statistic# = (select statistic# from v$statname where name = 'CPU used by this session') and stat.sid = sess.sid and stat.inst_id = sess.inst_id and (stat.value > 100 or i.physical_reads > 100 or i.block_gets > 100) and sess.username is not null and i.sid = sess.sid and i.inst_id = sess.inst_id), sqlarea as (select inst_id, sql_fulltext sql_text, hash_value, address from gv$sqlarea) select * from sessions, sqlarea where sessions.inst_id = sqlarea.inst_id and sessions.sql_hash_value = sqlarea.hash_value and sessions.sql_address = sqlarea.address order by cpu_used_by_this_session desc |
linux是多用户
操作系统,每一个用户在系统上都有一个唯一的id,这个id就是UID。
sh-3.2# id uid=0(root) gid=0(root) sh-3.2# |
id是一个数字,用户很难去记得一个数字到底对应的是哪个用户。
所以可以给每个用户分配一个用户名,这个用户名是用户敏感的。
用户名和UID的对应关系可以通过查看/etc/passwd知道,
sh-3.2# cat /etc/passwd root:x:0:0:root:/home:/bin/sh sh-3.2# |
linux系统还有群组的概念,每个用户在创建时可能就被指定到某个群组中。
而为了方便对群组的管理,所以也有了GID。
群组名和GID的对应关系可以通过查看/etc/group知道,
sh-3.2# cat /etc/group root:x:0:root sh-3.2# |
而群组又分为有效群组和初始群组,
用户所对应的初始群组可以查看/etc/passwd档案了解其中的对应关系;
用户所在的有效群组可以通过groups命令查看当前用户支援哪些群组。
sh-3.2# groups
root
sh-3.2#
以前一直搞不明白为什么文件权限是775,777,664或者是rwxrw-r-x之类的字串。
现在
学习了用户和用户组之后,终于知道为什么了,还是挺开心的。
sh-3.2# ls -lh /etc/passwd -rw-rw-r-- 1 root root 31 Jan 3 12:55 /etc/passwd sh-3.2# |
在上面文件权限这一栏中,第一个字符用来标识档案的类型,
是正规文件,还是目录,还是管道,还是链接文件?
http://blog.csdn.net/boyxulin1986/article/details/12655659
接下来三个字符表示的是文件所有者对文件所具有的权限;
在接下来三个字符表示的是文件所有者所在的群组所具有的权限;
在接下来的三个字符表示的是其它用户对文件所具有的权限。
所以如果想知道拥有某个指定文件的哪些权限,
必须要知道文件拥有者是谁,再查看用户与群组的对应关系。
这样再确定当前用户是文件拥有者、还是属于文件拥有者所属的群组还是其他用户。
注意:在多用户环境下,文件拥有者并不一定等于当前用户。
查看当前用户的方法是:
sh-3.2# id uid=0(root) gid=0(root) sh-3.2# |
查看文件拥有者的方法是:
sh-3.2# stat /etc/passwd File: "/etc/passwd" Size: 31 Blocks: 1 IO Block: 4096 regular file Device: fe00h/65024d Inode: 985 Links: 1 Access: (0664/-rw-rw-r--) Uid: ( 0/ root) Gid: ( 0/ root) Access: 2014-01-03 12:55:32.000000000 Modify: 2014-01-03 12:55:32.000000000 Change: 2014-01-03 12:55:32.000000000 sh-3.2# |
最后再了解一下文件权限中的sticky bit。
sh-# ls -ld /tmp/
drwxrwxrwt 5 root root 1020 Jan 1 00:03 /tmp/
sh-#
这个权限t就是目录或档案的sticky bit。
linux系统中的sticky bit只对目录有效,对文件设置sticky bit是没有意义的。
而对目录设置sticky bit的作用是:
对于目录中已有的文件,只有文件的owner和root有权限删除;
任何用户都可以在这个目录下创建或修改文件。
这样对于多用户环境而言,就不用担心档案被其它用户删除了。
增加sticky权限的方法如下,
sh-# mkdir ./temp sh-# ls -ld ./temp/ drwxr-xr-x 2 root root 40 Jan 1 00:21 ./temp/ sh-# sh-# chmod +t ./temp/ sh-# sh-# ls -ld ./temp/ drwxr-xr-t 2 root root 40 Jan 1 00:21 ./temp/ sh-# sh-# umask 0022 sh-# |
Ynm3k的iosMonkey脚本
Ynm3k是基于官方提供的UI Automation扩展的
自动化测试框架。
它的基本架构和功能参见 http://wenku.baidu.com/view/a513c2779b6648d7c1c746d3.html 这里只阐述其中iosMonkey.js脚本的使用,
使用步骤:
1、打开instruments,左侧选择设备(是真机还是模拟器),然后选择Automation工具
2、选择target
3、导入脚本
4、运行设置
导入后选择脚本编辑界面