作者根据他的经验, 整理了一些事情,让你知道它们是一些不好的思维, 不要在
测试过程中去做它们
1. Don’t leave all the testing to the QA department!
- 这意味着我们需要多做一点unit tests, 来帮助我们早点发现问题
- 这样才能让我们能花较少的时间和精力来解决它
2. Don’t leave the testing to the end!
- 真的, 当你一有什么就开始测试
- 包括tester一开始就加入design, 早期就加入开发的活动. 毕竟更了解产品, 会让我们测的更好
- 理想状况, dev和tester可以一起讨论, 什么东西要在unit testing作, 那些要在functional testing作, 那些要做automation, 或者load, performance , stress要做什么
3. Don’t try to automate everything!
- 测试自动化在回归测试上可以帮很大的忙, 但是它的cost也相当大
- 所以当你要花心力在测试自动化前, 请先分析他所能带来的报酬率是什么
- 如果它是很单纯, 并且是一个很普遍的例子, 可以考虑把它加到unit
test中.
- 如果它很复杂, 可能要考虑一下creation的cost, 以及维护的代价.
4. Don’t forget to test manually!
- 不要忘记, 测试自动化所能找到的bug, 都是你事前规划好所能找到的. 它不太能找到你事前没规划要找的bug
- 所以还是要靠人脑, 唯有人脑才能对你要测的功能不断思考.
5. Don’t think the product is completely tested!
- 有些产品出货好几年后, 仍然被顾客找到bug
- 不要能为你可以完整测试
6. Don’t get satisfied with the number of the passed tests!
- 通过了多少测试个案不重要, 也就是个数并不重要.
- 重点是思考你曾经做个哪些, 并且是否持续改进.
- 当客户找到bug时, 你觉得跟他讲说, 这个产品已经通过500个测试个案, 会有用吗? 他会听吗? 他可能只是会觉得你都没测就release了.
在说去年兰亭第一次搞这种大型促销活动之前,有必要跟大家说一下国外几个非常重要的购物节:
感恩节(Thanksgiving Day)
感恩节是每年11月的第四个星期四,由美国创立,原意是为了感谢上天赐予的好收成,是美国国定假日中最地道、最美国式的节日,和我国的春节一样重要。感恩节购物已经成为了美国人的习俗,从感恩节到圣诞节这一个月,总销售额能占到全年的1/3,是各个商家传统的打折促销旺季。
黑色星期五(Black Friday)
黑色星期五是感恩节的第二天,也就是11月的最后一个星期五,这一天是美国人圣诞节前的大采购日。美国的商场都会推出大量的打折和优惠活动,以在年底进行最后一次大规模的促销。因为美国的商场一般以红笔记录赤字,以黑笔记录盈利,疯狂的抢购使得商场利润大增,因此被称作"黑色星期五"。
以前黑五促销主要以实体百货为主,据说是因为周五这天一大早,所有人都要摸着黑冲到商场排队买便宜货。随着网络电子商务的发展,越来越多的大促搬到了网上,大家足不出户就可抢购,也给了很多人海淘的机会。
网购星期一(Cyber Monday)
网购星期一是美国感恩节后的第一个星期一,大约从2000年开始,美国亚马逊、eBay等电商会在这一天推出大规模促销活动,成为“黑色星期五”的电商版本,就是真正的网购节。
大促那些事儿
去年9月份的时候兰亭搞了第一次大促销,前前后后持续了一个月,当然肯定也不是这三个节日,而是兰亭自己推的大促,据知情人透露这是在清库存,把积压的库存变现,让上市后第一个Q的财报漂亮点。记得当时是第一次搞这种促销活动,很多部门都牵涉进来了,采购,物流仓储,运营部门,品类管理部门,产品技术以及创始人等等。而跟我们关联度最高的莫过于促销页面开发
测试及上线。当时大促是做四期,头三期是预热,最后一期才是促销商品的抢购。
如果要说产品复杂度,的确没有什么,最多就是要考虑到抢购时超卖情况以及开发一款网页游戏来抢Coupon(优惠券),另外增加了一种促销方式:秒杀,同时对于活动期内的秒杀商品需要在品类页,站内搜索页等等优先显示并打上秒杀图标,给用户以提示,除此之外,就是促销页面的开发,只不过当时最令大家头疼的就是分享到Facebook和Twitter等社交网站的功能,因为活动折扣价跟分享数和收藏数相关联,国内常受到第三方网络等影响,经常出现一些问题还需要排查到底是不是bug。而且做过
互联网的都知道,只要涉及到页面样式和交互比较多的,就有比较大的
工作量,很多样式的bug,兼容性的bug以及JS交互的bug。当然如果紧急上线肯定就需要做一些取舍,保证重要的功能没问题,其余的bug可以不予理睬,记得每一期发现二三十个bug,有一大半没有修复。
在我们拿到需求之后发现每一期的开发测试上线周期都只有两三天的时间,时间紧任务重,是摆在我们所有人面前的困难。为了保证大促的顺利进行,所有人都投入进来了,我们测试部门也对此做出了工作部署。把每一期功能或区块细分,同时把不同期的相同或相似的指派给2个人,这样每一期大概2~3个人参与,相同或相似的模块又不会没有backup,也不会造成同一个人连着做好几期的情况,后来证明这么部署是非常正确的。
当时大促的每一期都不轻松,基本都是要加班到凌晨2~3点,甚至好几天都是到了天亮才搞完,大家再回家休息,每一期其实都是不同的人参与,这样既能保证产品顺利发布,又能让加过班的同学第二天在家休息。记得当时有一次大家连着加班到第二天中午,我们早上去上班的时候还没有下班,接着把产品搞完上线,而晚上的时候也只是在公司办公桌趴了一会儿接着干活,相当辛苦,脸色也很憔悴。当时因为我正在学车,周末时的加班没有参加,平时我和其他两个人分工负责了每一期的上线,所以有时候也是要加班到很晚。当时有一期,公司其中一个创始人也跟着我们搞到凌晨12点,他在协调着几个大部门的工作,保证大促顺利开展。
在这之后不久,公司内刊的人邀请我写一篇大促的
文章,说说我的所见所感,毕竟这是公司第一次搞大规模的促销,盛情难却,抽了个晚上写了一下,后来发表了,并且选了一张自认为拍的最帅的照片刊登上了。后来到了年底又才有了Black Friday和Cyber Monday同样持续差不多一个月的大促销。同样是耗费了不少的时间和人力,当时大家其实都非常想搞一个通用的模板在线进行编辑生成大促页面内容,不用再投入技术人员,但是项目紧资源少,平时都没有空来做这个,不知道在我离开之后现在是什么样子。而且我参与过的这两次大促给我印象最深刻的就是没有提前规划,很多东西到了正开发的时候还在改需求,并没有像阿里和京东那样差不多提前几个月就在规划逐步开展大促项目,有条不紊。来了京东,也算是经历过一次618了,我觉得很有必要以后跟大家分享下我经历过的618,不知道大家感不感兴趣?
版权声明:本文出自 zzzmmmkkk 的51Testing软件测试博客:http://www.51testing.com/?258885
原创作品,转载时请务必以超链接形式标明本文原始出处、作者信息和本声明,否则将追究法律责任。
当你在开发应用的时候,大多数时候你都在写一些处理资源的代码。那些打开
数据库连接,分配内存之类的代码。更底层的就是和计算环境打交道的代码了。这些代码很恶心,尽管有些程序员特别好这一口,但怎么说,这种代码自然是越少越好。真正能产生商业价值的是那些处理业务逻辑的代码。当然,很明显你也不可能只写业务代码对吧。还有一类代码是用来运行这些业务代码的,当然了,基础架构和业务的代码的边界并不是那么清晰。你很难跟别人说这些是业务代码,那些是基础设施的代码。
你能做的就是选择一个适合业务场景的框架。那些比较容易配置,不需要大量模板代码,容易
学习的框架。这样的话你可以更聚焦于业务代码。当然了,知易行难。现在项目还有这么多的不确定性,你怎么才知道长期来看哪个框架最好?这个很难确定。不过你可以试一下,争取能更准确一些。有一个能遵循的选型的模型就最好了。那么在这里,这个模型应该是什么样的?
在一个项目的生命周期里,肯定是需要花费一些精力来开发业务逻辑的。如果业务逻辑是确定的,那么需要开发的代码量肯定不会变化太大。由于有些编程语言写起来可能比较啰嗦,代码量上面可能会略有不同。同时还有学习框架的成本,不过这个对于一个长期的项目而言可以忽略了。你只需要在项目的开始阶段费点工夫,比如中sprint中的1,2阶段,在那以后这个成本和整个的开发量相比就无足轻重了。对于我自己建立的这个模型而言,我会忽略掉这块的
工作,一个原因也是因为我没办法提前预估平均每个程序员大概需要多少时间来学习某个框架。
那么最终简化版的模型就是比较开发商业价值的代码以及配置和支持所选框架的代码之间的比例。怎么去衡量这个?
我通常是。。好吧,其实也算不上经常。选择框架也不是每天都干的事。我们团队上一次做这个选择的时候是这样的:
我们先选取了5个可选的框架。第一轮我们先剔除掉了一个并不是太有名用的也不是很多的框架。我们也不想赶这个时髦。另一个被淘汰掉是因为最近的一次调查表明这个框架完全不适合我们。那么还剩三个。最后我们在GitHub中去搜索那些使用到了其中某个框架的项目,每个框架至少挑两个。我们一共看了8个项目,去统计它们的业务代码和框架代码之间的比例。紧接着我们意识到,在有限的生命中这个是完成不了的,因此我们将它简化了下。我们开始按类的名字对它们进行分类。有一些业务类的名字是和业务数据相关的,有些是以某些业务功能来命名的。剩下的那些都认为是框架支持、配置的类。
最终的成果写到了之前的一个PPT中,我们加了两页幻灯片来分析这三个框架的优点及缺点。毫无疑问,最终的结果高度一致:计算表明,框架需要的配置和支持代码越少,大家就越喜欢。
那么这个选型的附加价值是什么?
做这个
测试我们必须去审查项目,同时我们也学到了很多关于这些框架的知识。虽然和正常写代码没法比,但总比盯着那些宣传资料要强。我们接触了开发人员在面临实际的问题以及实际的框架特性时所写出的实际代码。这有助于评估员了解到更多的知识,让他能快速提高,以便让我们知道什么是该注意的,什么是该去尝试的。
还有一个尤其重要的结果就是,我们对这个决策的结果没有太多疑问。如果结果是相反的,那么麻烦就大了,这会让我们很困惑:为什么大家会选择一个需要更多与业务无关代码的框架。不过所幸没有。结果跟我们的直觉一致。
那么我是不是推荐使用这种方式来进行框架选型呢?当然不是。不过它可以作为 一个很好的补充,这只会花掉你的SCRUM团队的两到三天的时间而已,而且这还能让你的团队接触一下新的技术。
很多人常常问, 如何得知
test cases是否已经开得足够了, 是否已经cover所有的范围了, 这还真的是很难回答的问题, 但是也是各很值得大家一起讨论的问题.
因此小弟在此先抛砖引玉, 先列出一些个人的看法, 希望大家能够一起参予讨论, 贡献一下不同的想法
1. Requirement - Test Cases Mapping
常见的手法, 是建立requriement/design 和test case的对应关系. 这样你便可以知道, 是否每个requirement已经有对应的test cases. 如果没有对应的部份, 便要加开 test case
Pro
- 容易开始作
- 提供一个high level mapping relationship
- 有这样的关系, 之后还可以进一步做一些分析, 例如
bug, test cases和requirement的关系
Con
- 不容易对所有细项功能都做这样的mapping, 会花大多时间
- 通常常没有requriement/design的文件, 所以想mapping也mapping不起来.
2. Test Coverage
经由coverage ratio你便可以知道哪些地方没有测到, 便可以要求加开test case
Pro
- 可以精确知道哪里没有test case包含到
Con
- 不是所有系统都可以找到可以使用的coverage tool
- coverage criteria是一个重点, all statement coverage 100%, 和all decision coverage 100%是不同程度的coverage. all statement coverage 100%只是最低程度的要求(我是以学术研究的角度来看, 呵呵)
- 如果都不写erro handling的程序, coverage ratio通常最高, 但我想这应该不是你要的结果
- 需要RD协助, QA才能进行的比较顺利. 因为要分辨3-party的 codes, 或是exception handling, error handling的执行, 这些地方常需要RD帮助才能做到
3. Beta Bugs
由Beta 所找到的bugs分布或是数量, 可以知道目前的test case是否已经足够了. 若是有些部分被找到很多bug, 那便是这部份的test case还不足够
Pro
- 可以提供不同的角度来验证是否足够, 尤其这是real world的观点
Con
- 这个时间点已经在项目后期, 因此可能会让你没有时间再补开更多test cases, RD也可能没有时间作design的修改.
- 可能有些公司是没有Beta这个阶段, 所以你没办法有这样的信息
- 有些project是不需要Beta这个阶段, 所以你没办法有这样的信息
4. Alpha Bugs
由Alpha所找到的bugs分布或是数量, 可以知道目前的test case是否已经足够了. 若是有些部分被找到很多bug, 那便是这部份的test case还不足够. 和Beta不同的是, 一定会有Alpha这个阶段
Pro
- 可以根据找到的bug, 再加开test case以增加完整性
Con
- 在Alpha阶段, 就要能一边
测试, 一边review测试个案是否足够, 否则也是会太慢才得知不够
5. History data
可以根据历史数据, 来得知是否已经开足够的test case. 例如大约多少行的程序要开立多少的test case. 或是多少test case害找多少bug. 用他们还回推是否test case已经足够
Pro
- 通常下一个版本时, team的能力不会改变太多, 所以出来的数据是蛮准确的. 不会因为你做过一次或是功能不同, 而会差太多
Con
- 真尴尬的是, 大部分的公司或是team, 没有记下任何历史数据
- 如果是1.0的版本, 可能也没有数据可以参考
6. Test Case Type
在开立测试个案之前, 先将测试个案分类, 至于要分成哪些类别, 可以根据team的需求自行定义. 因此当QA在开case时, 要对其test case分类, 之后便可以检查是否他所开立的case种类涵盖度够. 可参考以下文章, 知道更进一步作法
http://www.wretch.cc/blog/kojenchieh/12801500
Pro
- 若是你没有分类, 这个QA所开的case可能都只是属于某几类, 即使个数很多, 代表性可能也不够
- 训练QA能从更多面向来思考
- 若是之后发现某些类别(type)要增加, 可以在要求所有QA针对这项目来加开
Con
- 要有哪些类别(Type)不容易定义完整
- 有些类别(type), QA不知道那是什么或是要怎么开case. 例如 security test case, state based test case等等.
English » | | | | | | | | |
Text-to-speech function is limited to 100 characters
该10大iOS开发者最喜爱的库由“iOS辅导团队”成员Marcelo Fabri组织投票选举而得,参与者包括开发者团队,iOS辅导团队以及行业嘉宾。每个团队都要根据以下规则选出五个最好的库:1)不能投自己写的库;2)排除大的架构,比如游戏类架构;3)排除不在设备上运行的库,例如CocoaPods或者Rack::CoreData也排除在外。
最终评选出了如下10大iOS开发者最喜爱的库:
1)SSToolkit
Sam Soffes简直就是一个Objective-C天才,SSToolkit就是个例子。作者将他在App中实现的各种各样的UI效果做成个代码库,方便其他人使用。
SSToolkit一些基础的类包括SSCollectionView,SSGradientView
从UI部件到便利的Foundation类别都经过精心设计并记录在案,帮助开发者解决一些普遍问题,比如追踪一款设备是否有视网膜显示屏或者是否能剪裁图片
2)GPUImage
GPUImage一个功能十分强大又十分易用的图像处理库。
提供各种各样的图像处理滤镜,并且支持照相机和摄像机的实时滤镜
是基于GPU的图像加速,图像处理速度超快,并且能够自定义图像滤镜
支持ARC
不过现在还缺少一些Core Image拥有的一些先进功能,比如面部探测。
滤镜效果图
3)SocketRocket
SocketRocket是一个WebSocket客户端(WebSocket是适用于Web应用的下一代全双工通讯协议,被称为“Web的TCP”,它实现了浏览器与服务器的双向通信),采用Object-C编写。超级稳固又简单易用,简直就是实时应用的最佳拍档。
SocketRocket遵循最新的WebSocket规范RFC 6455
只有部分比较新的浏览器比如Chrome支持这个库
支持TLS (wss),iOS 4.x系统
使用NSStream/CFNetworking(可免费享用)、使用ARC
采用并行架构
大部分的
工作由后端的工作完成、基于委托编程。无任何UI包依赖。
因为Square,才有了SocketRocket
4)HockeyKit
HockeyKit是一个iOS Ad-Hoc自动更新框架。所有的
苹果店中的App都可以使用它,它能显著提高整个Beta测试过程,分为两部分:服务器和客户端框架。服务端组件不需要客户端库就能单独工作。
只需在服务器上安装一次服务端,就可以处理bundle identifier不同的多个应用程序(有开发者强烈建议对Debug、AdHocBeta和AppStore发布版使用不同的Bundle identifier)
默认当App启动或唤醒时,客户端会从服务器检测更新,用户可以在设置对话框中修改这个设置:一天一次或手动检测更新
除了支持iOS,HokeyKit也支持
Android平台,不过Android版还处在Alpha阶段,支持OTA及应用内更新
为HockeyKit用户提供服务器托管服务
Beta测试演示
5)JSONKit
JSONKit是Objective C平台上比较常用的JSON数据访问工具。
JSONKit能在运行的情况下与libz.dylib自动连接而无须人工连接
在解析期间,如果检测到有gzip文件,JSONKit能自动解压
速度超快,支持之前的iOS版本(但要注意一点,从iOS 5开始,iOS就已经有本地JSON解析工具了)
JSONKit的性能远优于JSON-Framework(即SBJSON),JSONKit使用起来也非常简单,表现性能比苹果iOS 5.0中的NSJSONSerialization还要好,速度比NSJSONSerialization快上25% to 40%,已经是非常大的一个差距了
Benchmark测试结果图
package com.eiyoung.wechat.web.controller; import java.io.IOException; import java.io.PrintWriter; import java.util.Date; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import com.eiyoung.wechat.web.utils.Message; import com.eiyoung.wechat.web.utils.ReplyMessage; import org.apache.commons.io.IOUtils; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; public class WeChat extends HttpServlet { private static final long serialVersionUID = 1L; public WeChat() { super(); * 验证 * @param request * @param response * @throws ServletException * @throws IOException protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); String echo = request.getParameter("echostr"); System.out.print(echo); echo = new String(echo.getBytes("ISO-8859-1"),"UTF-8"); pw.println(echo); protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { response.setContentType("text/html;charset=UTF-8"); PrintWriter pw = response.getWriter(); String wxMsgXml = IOUtils.toString(request.getInputStream(),"utf-8"); Message textMsg = null; try { textMsg = getMessage(wxMsgXml); } catch (Exception e) { e.printStackTrace(); StringBuffer replyMsg = new StringBuffer(); if(textMsg != null){ //增加你所需要的处理逻辑,这里只是简单重复消息 replyMsg.append("您给我的消息是:"); replyMsg.append(textMsg.getContent()); else{ replyMsg.append(":)不是文本的消息,我暂时看不懂"); String returnXml = getReplyMessage(replyMsg.toString(), textMsg.getFromUserName(),textMsg.getToUserName()); System.out.print(textMsg.toString()); System.out.print(returnXml.toString()); pw.println(returnXml); private Message getMessage(String xml){ XStream xstream = new XStream(new DomDriver()); xstream.alias("xml", Message.class); xstream.aliasField("ToUserName", Message.class, "toUserName"); xstream.aliasField("FromUserName", Message.class, "fromUserName"); xstream.aliasField("CreateTime", Message.class, "createTime"); xstream.aliasField("MsgType", Message.class, "messageType"); xstream.aliasField("Content", Message.class, "content"); xstream.aliasField("MsgId", Message.class, "msgId"); Message Message = (Message)xstream.fromXML(xml); return Message; private String getReplyMessage(String replyMsg,String toUserName,String fromUserName){ ReplyMessage we = new ReplyMessage(); we.setMessageType("text"); we.setFuncFlag("0"); we.setCreateTime(new Long(new Date().getTime()).toString()); we.setContent(replyMsg); we.setToUserName(toUserName); we.setFromUserName(fromUserName); XStream xstream = new XStream(new DomDriver()); xstream.alias("xml", ReplyMessage.class); xstream.aliasField("ToUserName", ReplyMessage.class, "toUserName"); xstream.aliasField("FromUserName", ReplyMessage.class, "fromUserName"); xstream.aliasField("CreateTime", ReplyMessage.class, "createTime"); xstream.aliasField("MsgType", ReplyMessage.class, "messageType"); xstream.aliasField("Content", ReplyMessage.class, "content"); xstream.aliasField("FuncFlag", ReplyMessage.class, "funcFlag"); String xml =xstream.toXML(we); return xml; package com.eiyoung.wechat.web.utils; * Created with IntelliJ IDEA. * User: sb * Date: 8/1/13 * Time: 10:37 PM * To change this template use File | Settings | File Templates. public class ReplyMessage { private String FuncFlag;//消息编号 private String fromUserName;//发送人 private String toUserName;//接收人 private String content;//内容 private String messageType;//消息类型 private String createTime;//创建日期 |
public String getContent() {
return content;
public void setContent(String content) {
this.content = content;
public String getMessageType() {
return messageType;
public void setMessageType(String messageType) {
this.messageType = messageType;
public String getFromUserName() {
return fromUserName;
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
public String getToUserName() {
return toUserName;
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
public String getCreateTime() {
return createTime;
public void setCreateTime(String createTime) {
this.createTime = createTime;
public String getFuncFlag() {
return FuncFlag;
public void setFuncFlag(String funcFlag) {
FuncFlag = funcFlag;
public String toString(){
return "createTime:"+getCreateTime()+"\ntoUserName:"+getToUserName()+"\n FromUserName:"+getFromUserName()+"\nmessageType:"+getMessageType()+"\ncontent:"+getContent();http://www.huiyi8.com/tishiyin/ 提示音
package com.eiyoung.wechat.web.utils;
import java.util.Date;
* Created with IntelliJ IDEA.
* User: sb
* Date: 8/1/13
* Time: 10:37 PM
* To change this template use File | Settings | File Templates.
public class Message {
private String msgId;//消息编号
private String fromUserName;//发送人
private String toUserName;//接收人
private String content;//内容
private String messageType;//消息类型
private String createTime;//创建日期
public String getContent() {
return content;
public void setContent(String content) {
this.content = content;
public String getMessageType() {
return messageType;
public void setMessageType(String messageType) {
this.messageType = messageType;
public String getFromUserName() {
return fromUserName;
public void setFromUserName(String fromUserName) {
this.fromUserName = fromUserName;
public String getToUserName() {
return toUserName;
public void setToUserName(String toUserName) {
this.toUserName = toUserName;
public String getCreateTime() {
return createTime;
public void setCreateTime(String createTime) {
this.createTime = createTime;
public String getMsgId() {
return msgId;
public void setMsgId(String msgId) {
this.msgId = msgId;
public String toString(){
return "msgId:"+getMsgId()+"\ncreateTime:"+getCreateTime()+"\ntoUserName:"+getToUserName()+"\n FromUserName:"+getFromUserName()+"\nmessageType:"+getMessageType()+"\ncontent:"+getContent();
maven
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>3.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>servlet-api</artifactId>
<version>3.0-alpha-1</version>
</dependency>
<dependency>
<groupId>joda-time</groupId>
<artifactId>joda-time</artifactId>
<version>2.2</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-io</artifactId>
<version>1.3.2</version>
</dependency>
<dependency>
<groupId>com.thoughtworks.xstream</groupId>
<artifactId>xstream</artifactId>
<version>1.4.3</version>
</dependency>
</dependencies>
select p.spid,c.object_name,b.session_id,b.oracle_username,b.os_user_name from v$process p,v$session a, v$locked_object b,all_objects c where p.addr=a.paddr and a.process=b.process and c.object_id=b.object_id
能查询到死锁的表名
SELECT s.username,l.OBJECT_ID,l.SESSION_ID,s.SERIAL#,
l.ORACLE_USERNAME,l.OS_USER_NAME,l.PROCESS
FROM V$LOCKED_OBJECT l,V$SESSION S WHERE l.SESSION_ID=S.SID;
查询到死锁的session_id, serial#
alter system kill session 'sid,serial#'; (其中sid=l.session_id)
杀死死锁的进程
还记得刚
学习计算机时,书上将计算机系统定义为硬件系统(计算机),软件系统(
操作系统)和操作者(人)。这样的定义与多数人认为的”系统=机器”的理解完全不同。在和
配置管理打交道的过程中,我也有过类似的经历。最开始以为SVN系统就是配置管理系统,到逐渐地对“一套配置管理系统应该是什么样子”有了自己的认识。
在笔者看来,一套能够满足企业需求的配置管理系统应该包括三方面:
硬件: 服务器+应用系统
软件: 规程、规范、文档、流程
人: 项目配置管理员、组织级配置工程师,构建工程师等
搭载应用系统(如SVN, CC, git,maven, bugfree, hudson等)的服务器(群)是配置管理的硬件基础。毕竟基本的版本控制、自动构建、缺陷跟踪还得靠软件应用系统来实现。
规程(配置、变更),规范和文档,以及基于这些规程规范建立的审批流程,是这个系统的软件部分。
最后,系统都需要有人来管理、使用,按项目和产品线来安排配置管理员,将相关的责任分配到个人,是保重规程规范能够落实的基本条件。组织级的配置管理工程师负责配置系统的管理,不参与项目的具体操作(评审和审计除外)。其它参与配置管理的角色还有: 构建工程师,项目经理(主要是审批),QA(主要是审计)等。
三者缺一不可,紧密配合,才能构成一套支持企业正常运转的配置管理系统。
近来我遇到越来越多的人对我们会发布还有
bug的产品大为惊讶。而让我大吃一惊的是,这些人中还有许多是
软件测试人员,我本以为他们应该对此早已经有所了解。建议大家先阅读Eric Sink较早写的(但是很棒的)
文章。不知道我还能对此话题有多少贡献,但我想试试。
许多bug并不值得去修复。“你这也算是测试人员吗?”,你肯定会冲我大叫,“测试人员是产品质量的捍卫者。”我可以再重复一次(如果需要的话)许多bug并不值得去修复。“让我来告诉你原因。在大多数情况下,修复bug就必须要修改代码。而修改代码需要投入资源(时间)并会引入风险。这真是很糟糕,但这却是事实。有时,如果风险和投入远超过修复bug的价值,因此我们就不会被修复这些bug。
我们决定是否修复一个bug并不是,也不应该是靠“感觉”。我喜欢用“用户痛苦”的概念来帮助我做决定。我会用三个关键因素来考虑并确定“用户痛苦”:
1、严重性—— 这个bug将产生什么影响 —— 它会让整个程序崩溃吗?它会导致用户的信息丢失吗?或者并不是那么严重?有更简单的解决方法吗?还是它仅仅是个无关紧要的问题?
2、频繁性—— 用户碰到这个问题的频率高吗?它是程序主要
工作流程中的一部分?还是隐藏在一个并不常用的功能中?在最常用的那部分程序中存在的小问题很可能是需要修复的,而一些不常用到的那部分程序中存在的大问题,也许我们会放在一边。
3、对客户的影响——如果你之前准备工作做得好,你应该已经知道你的客户是谁,你的每个客户群中会有多少(或者是你希望有多少)用户。这样你就需要判断,这个问题将会影响到每位用户一,还是仅仅一部分人。如果你能追踪出客户如何使用你的产品,你就能得到更准确的数据。
以上3点因素就构成了一个公式。给上面的每一个因素都分配一个数值范围,并且用一些计算 —— 你可以直接使用加法、乘法或是基于你的应用程序以及市场因素加上权值。打个比方,我们只需要执行加法并且对每个bug赋予10分的数值范围。
Bug #1:比如它是一个会让程序崩溃的bug(10分),它存在于程序的主要部分(10分),它影响了80%的客户(8分),因此这个bug的”用户痛苦“量值为28分,我们打赌我们肯定会修复它。
Bug #2:它仅仅是一个关于排列的bug(2分),它出现在二级窗口中(2分),这个bug所在的那部分程序只会在旧版本中被使用到(2分)。因此这个bug的“用户痛苦” 量值为6分,我们很可能不会去修复它了。
遗憾的是,很多情况并不像上面所说的那么简单。Bug #3是一个数据丢失问题(10分),它存在于一个应用程序的某个主要部分中,却只在某些特定的情况下才出错(5分)(顺便提一下,数据是主观编造出的)。客户研究证明它很少会被使用(2分)。因此它的 “用户痛苦”量值为17分,这是一个模棱两可的数据,修与不修都可以。一方面,修复它所需要的投入可能并不值得,只要这个问题能够被理解,并且它没有任何盲点,不再理会这个bug很可能是正确的处理方法。
从另一方面来看,你必须把它和系统中的其他bug进行权衡。我们在这里应用“破窗效应(Broken Window)”—— 如果应用程序中有太多此类中等阈值的bug,产品的质量(或者最起码,从质量的感觉上)一定大受影响。你在考虑系统中每一个bug的时候,还应该结合考虑系统中其他(已知的)bug,并且以此来分析、决定哪些bug是需要被修复的而哪些则不值得被修复。
正式发布的软件中有bug的确是一件十分糟糕的事 —— 但基于我们现有的开发工具和开发语言,我们还没有找到一个更加合理的解决方法。
补充:
写出这篇文章的时候,我想我遗漏了公式中的第四个因素:发布日期。临近发布日期时,这个因素在修复/不修复bug的决定中也起了关键作用。然而我并不确定它是否是第四个因素,也无法确定在临近发布时期时,修复一个bug所需要的 “用户痛苦”量值的阈值是多少。
Resharper是一款很优秀的重构工具,已经习惯了Resharper快捷键,利用Resharper做重构,TDD开发,很爽。唯一缺点就是低配置机器上速度很慢,容易拖死VS,
为此我我专门把我的本本换成6G内存,现在感觉顺畅多了。
回到正题,我在项目中运用了
XUnit,但是VS和Resharper对其快捷键都还不能默认支持,所以在网上找到扩展Resharper使其支持Xunit,步骤如下:
关闭所有VS。
在http://xunitcontrib.codeplex.com/下载xUnit.net Contrib
把目录中的xunitcontrib.runner.resharper.Resharper版本号拷贝到C:\Program Files\JetBrains\ReSharper\Resharper版本号\bin\plugins 下(其中的plugins可能需要手动建立)。同样你也可以拷贝到<RoamingAppData>\JetBrains\ReSharper\Resharper版本号\vs版本号\plugins
拷贝resharper.external.annotations\xunit.xml到C:\Program Files\JetBrains\ReSharper\Resharper版本号\bin\ExternalAnnotations目录下。
开启VS。
ReSharper -> Live Templates ->"Import" 导入xunit-ae.xml或者xunit-xe.xml。xunit-xe.xml和xunit-ae.xml对XUnit断言语句的扩展简化,xunit-xe.xml以x开头,比如xe => Assert.Equal,而xunit-ae.xml则以a开头,比如ae => Assert.Equal。
最后大功告成。