作者根據他的經驗, 整理了一些事情,讓你知道它們是一些不好的思維, 不要在
測試過程中去做它們
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。
最后大功告成。