<rt id="bn8ez"></rt>
<label id="bn8ez"></label>

  • <span id="bn8ez"></span>

    <label id="bn8ez"><meter id="bn8ez"></meter></label>

    qileilove

    blog已經轉移至github,大家請訪問 http://qaseven.github.io/

    Python編程中的反模式

     Python是時下最熱門的編程語言之一了。簡潔而富有表達力的語法,兩三行代碼往往就能解決十來行C代碼才能解決的問題;豐富的標準庫和第三方庫,大大節約了開發時間,使它成為那些對性能沒有嚴苛要求的開發任務的首選;強大而活躍的社區,齊全的文檔,也使很多編程的初學者選擇了它作為自己的第一門編程語言。甚至有國外的報道稱,Python已經成為了美國頂尖大學里最受歡迎的編程入門教學語言。
      要學好一門編程語言實屬不易,在初學階段,就糾正一些錯誤的做法,對今后的深入學習至關重要。有一位叫Constantine Lignos的博主,他是賓夕法尼亞兒童醫院放射研究部門的博士后研究員,他最近撰寫了一篇很有意義的文章,列舉了初學Python的學生們最常犯的錯誤,并對這些錯誤進行了分類和剖析,其內容提綱挈領,非常值得每個Python初學者學習。
      這篇文章給出了一些在Python初學者中很常見的反模式,反模式通常是指那些不符合習慣或者會導致糟糕后果的用法。Lignos把他總結的反模式分成了四大類——迭代、性能、變量的漏洞和編程風格。下面我們逐一來看一個例子,理解這些反模式到底“反”在什么地方。
      迭代
      當我們需要簡單迭代一個數量范圍的時候,Python給了我們一個非常好用的函數:range。Lignos觀察到有些初學者喜歡用range來迭代列表的下表,像下面這種形式:
      for i in range(len(alist)):
      print alist[i]
      這代碼現在還沒什么問題,但已經不符合Python的習慣了。但下面的代碼就有問題了:
      alist = ['her', 'name', 'is', 'rio']
      for i in range(0, len(alist) - 1): # 漏掉了最后一個
      print i, alist[i]
      我們可以看一下Python官方文檔range的示例:
      >>> range(1, 11)
      [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
      range的右區間是不包含在內的,如果受了直覺或其他編程語言的影響,再減1就不對了。Lignos還列舉了其他幾種錯誤的迭代模式,我們只要記住,range應該用在迭代一個數量范圍。
      性能
      Lignos給出了兩段代碼:
      lyrics_list = ['her', 'name', 'is', 'rio']
      words = make_wordlist()
      for word in words:
      if word in lyrics_list: # 線性時間
      print word, "is in the lyrics"
      和
      lyrics_set = set(lyrics_list)
      words = make_wordlist()
      for word in words:
      if word in lyrics_set: # 常數時間
      print word, "is in the lyrics"
      哪種模式效率更高?Lignos注釋已經給出了答案。注釋的意思是,判斷一個元素是否在一組元素中存在,使用list的算法復雜度是O(n),而使用set的算法復雜度是O(1)。那是否set永遠是優于list?在其他情況下,應該用哪個數據結構?Python官方Wiki有一份專門各個數據結構操作的時間復雜度的文檔供參考,知道參考這份文檔比答案本身更重要。至于為什么,只有Python的源碼才能告訴我們。
     變量的漏洞
      初學者往往會假設一些不該假設的前提,對一些異常流程考慮不周。Lignos也給了一個例子:
      for idx, value in enumerate(y):
      if value > max_value:
      break
      processList(y, idx)
      這里y如果是空的,那就出問題了,因為idx根本得不到定義,最終我們會得到一個NameError的異常。比較好的做法是給idx一個默認的錯誤值,在C語言里面我們經常喜歡用-1。下面的代碼就考慮得比較全面:
      def find_item(item, alist):
      # 對Python來說None比-1可能更好點
      result = -1
      for idx, other_item in enumerate(alist):
      if other_item == item:
      result = idx
      break
      return result
      代碼風格
      Python有一份代碼風格指導文檔PEP 8,這些規則都是有道理的。當初學者不明白為什么的時候,最好的做法就是盡量遵守它,等到有更深入的理解了就會豁然開朗,同事也會明白什么時候可以打破規則。Lignos引用了這份文檔的一些例子,比如,如何測試一個變量是否為空,如果測試一個變量是否為None等等。
      以上分析了這篇文章中的一些例子,如果希望全面了解,請查看原文。想要學好一門編程語言,學會語法是遠遠不夠的,必須逐步理解語言所依賴的CPU體系結構、編譯器/解釋器/虛擬機等內容。Lignos這篇文章雖然沒有深入剖析Python的實現,但是對于入門者的幫助是非常明顯的,當初學者有了一定經驗后,對一些問題都可以做深入挖掘,引出Python實現層面的問題。

    posted @ 2014-07-18 09:59 順其自然EVO 閱讀(171) | 評論 (0)編輯 收藏

    測試經驗的總結

      軟件職業生涯總結
      項目一:MTK應用軟件測試
      產品流程為:產品立項---產品定義--產品設計開發---提交產品---開發人員測試(開發部有一人專測)----產品部驗證產品(轉下)
      1)有BUG轉到開發部門進行修復,修改后再次驗證,驗證通過轉到第2點
      2)無BUG直接與中間件通訊進行資費測試
      項目二:智能視頻監控軟件測試(C/S   B/S 版測試)
      產品流程為:產品立項----產品設計開發---提交產品---測試人員根據實現功能進行測試--BUG提交---BUG修復---BUG關閉
      測試內部流程: 編寫測試方案---編寫測試用例--提交新版本執行用例---BUG提交與跟蹤---BUG的修復與驗證----測試回歸測試(回歸只針對修改部分進行詳細測試,其它未改動部分正常功能測試)--多個基線回歸測試---后期使用手冊的編寫
      項目三:APP應用
      產品流程:產品市場調研---產品需求定義---產品設計開發---測試----回歸測試----測試報告---上線
      測試內部流程:熟悉需求---編寫測試用例---執行測試用例---回歸測試---編寫簡潔測試報告---產品上線測試
      以上為本人所在公司的一些工作流程,個人以為都不太完善。因為都是一些小公司很多流程就省略了,都說一些大公司的流程比較規范,各位大俠一起分享喲!
      以下為個人對流程的一些想法,請多多指教!
      軟件生命周期:
      產品產項---產品定義---產品需求----需求評審(個人覺得測試很有必要參加這個評審會議)---確定需求---產品設計---產品編碼----產品成型----測試---回歸測試---測試報告---維護
      (產品成型后如若能安排時間與測試人員互動,讓測試人員了解開發的一些設計邏輯或業務流程對測試人員那是相當的有幫助,目前所有公司軟件的業務流程都是測試人員一個個去問的,想深度發現BUG一定要了解業務流程,否則只能發現一些表面的問題)
      IOS應用測試流程一:
      第一步:遍歷自己模塊,查看大的功能點是否已實現
      1)未實現   拒絕測試轉給開發人員內測
      2)已實現   轉到正常流程測試,轉第二步
      第二步:執行所有的測試用例
      1)優先執行正常功能的用例
      2)執行異常的用例
      3)按模塊執行用例,即正常的異常的一起執行
      此不知各位覺得哪個好些呢,我們實際操作都是按的3來的,每次時間都覺得很緊的?
      第三步:BUG的提交與跟蹤
      提交的BUG即使告知開發人員,功能BUG直接描述,對于一些涉及到UI的問題截圖加附件以便開發人員知道具體的現象。
      第四步:提交新的基線測試
      1)驗證上一輪BUG修復情況,未修復轉給開發人員;已修復關閉BUG
      2)驗證BUG完畢后進行正常功能的驗證,時間允許的話執行正常功能用例
      第五步:重復第四步,執到所有BUG均已修復,或大部分BUG已修復
      第六步:遍歷所有模塊的正常功能測試(測試環境),提交測試環境測試報告
      第七步:生產環境的測試(所有正常功能的測試),提交生產環境測試報告
      第八步: 產品上線后的驗證測試

    posted @ 2014-07-18 09:58 順其自然EVO 閱讀(209) | 評論 (0)編輯 收藏

    Windows下 OpenAcs測試平臺搭建

      OpenAcs從ACS測試演變過來,由于我是實習生,在公司還沒呆兩天,所以搭建建個平臺先練練手,順便熟悉下公司的業務.
      順便提一下,我實習公司是NetCore.
      搭建大體流程以及軟件
      搭建環境:
      Windows7X64,其他環境自測
      所需軟件(其他版本自測):
      jdk-6u45-windows-x64
      jboss-4.2.3.GA
      mysql-5.5.28-winx64
      還有openacs的相關文件,我是從http://sourceforge.net/projects/openacs/files/?source=navbar的虛擬機里面搞出來的:
      acs.ear
      openacs-ds.xml
      openacs-service.xml
      openacs-bin-0.4.zip(貌似這些openacs文件csdn上面有的,去找找吧)
      安裝流程:
      1.安裝jdk并配置環境(不會的百度)
      2.解壓JBOSS到某個目錄下,直接進行環境配置
      JBOSS_HOME  .;D:\jboss-4.2.3.GA
      path  D:\jboss-4.2.3.GA\bin
      運行run.bat(如果上述環境配置成功,直接在CMD下運行run.bat)
      訪問http://localhost:8080, 能訪問說明JDK和JBOSS均安裝成功.
      3.安裝mysql 建立用戶 建立數據庫 并授予新用戶權限
      安裝好mysql后
      在cmd下mysql -u root -p(未設置root密碼的,百度mysql root密碼設置 記住默認密碼為空,直接回車)
      我的版本的MySql建立用戶時用如下
      insert into mysql.user(Host,User,Password)values("localhost","openacs",password("openacs"));
     之后刷新數據庫
      flush privileges;
      再quit下,測試用openacs賬號是否能成功登入
      切換到root進行數據庫創建及授權
      create database acs ;
      flush privileges;
      grant select,insert,update,delete,create,drop,index on acs.* to openacs@localhost identified by 'openacs';
      4.連接數據庫
      將mysql-connector-java-5.1.18.jar
      復制到$(JBOSS_HOME)/server/default/lib/.如果沒有就先下載。
      5.配置openacs
      復制acs.ear到JBOSS_HOME \server\default\deploy ,不修改。
      復制openacs-ds.xml到JBOSS_HOME\server\default\deploy
      這里需要修改openacs-ds.xml中數據庫連接的用戶名和密碼,打開該文件,設置用戶名和密碼為我們之前設置的用戶,即openacs,
      還要修改地址這里將connection-url>的值設置成jdbc:mysql://localhost/ACS,因為我的數據庫在本機。
      復制openacs-service.xml到JBOSS_HOME\server\default\deploy\jms,不需要修改。
      6.開啟服務并測試
      運行JBoss控制臺run.bat
      開啟mysql服務

    posted @ 2014-07-18 09:56 順其自然EVO 閱讀(943) | 評論 (0)編輯 收藏

    探索性測試之個人筆記

      對于一“新新”事物(對測試者而言的:測試內容或對象),根據自己預先設置的測試流程,測試用例,測試方法,進行一種嘗試性的測試。
      在測試過程中要注意幾點:
      1.測試過程,就是一個不斷對于自己設計的測試流程,測試用例(TestCase),測試方法的一種檢驗,同時也要不斷思考新的,好的方法或用例;
      2.測試過程是強調個人的主觀能動性,這個過程強調了,作為一個測試人員,你的意愿,你的行為將在很大程度上影響者這個測試執行力度;
      3.不斷的積累,由于對于測試的不斷深入,也開始逐步的了解測試的內容,這時,就要不斷的記錄,累積,和重構你的測試,逐漸的區建立一種完整的,全面的測試方案。
      就個人當前的水平,認為,對于一般的軟件測試————黑盒測試,主要進行一下幾個方面的測試用例編寫,以及執行
      (1)功能性測試
      (2)文檔測試
      (3)性能測試
      (4)性能測試
      (5)兼容性測試
      (6)環境配置測試
      …………
      當然這只是說了測試應該進行過程中應該考慮的測試方面,在編寫測試用例過程中,你要考慮一個重要的因素就是,如何將測試方法,測試技術體現在測試用例中。通過對測試用例的執行就可以完成我們所預期的測試覆蓋率,以及測試的全面的完整。
      這里可以重一下三個方面的探索:
      1.測試的對象的屬性,你測試的對象是什么,你對它的了解程度————越熟悉越好
      2.個人的經驗,自己的個人經驗的積累有時是一種很好的參考方式(如果沒有,那慢慢積累)
      3.不斷地與人交流,溝通的方式,有時可以幫助我們獲得意想不到的收獲,這就是語言的力量,溝通的魅力
      …………
      這些只是個人的一點點小感悟吧~~~·

    posted @ 2014-07-18 09:55 順其自然EVO 閱讀(159) | 評論 (0)編輯 收藏

    數據庫中的左連接和右連接的區別

      今天,別人問我一個問題:數據庫中的左連接和右連接有什么區別?如果有A,B兩張表,A表有3條數據,B表有4條數據,通過左連接和右連接,查詢出的數據條數最少是多少條?最多是多少條?
      我被這個問題問住了,后來我去問了數據庫開發人員,結果結果各種各樣:
      a 最大12  最小0
      b 最大12  最小未知
      c 最大未知 最小為3
      d 最大12   最小為3
      e 不清楚
      1、說明
      (1)左連接:只要左邊表中有記錄,數據就能檢索出來,而右邊有
      的記錄必要在左邊表中有的記錄才能被檢索出來
      (2)右連接:右連接是只要右邊表中有記錄,數據就能檢索出來
      2、舉例說明
      新建兩張表,分別為t_left_tab和t_right_tab
      將t_left_tab作為左邊表,t_right_tab作為右邊
      左連接:SELECT * FROM t_left_tab a LEFT JOIN t_right_tab b ON a.`id` = b.`id`;
      查詢結果:
      右連接:SELECT * FROM t_right_tab a LEFT JOIN t_left_tab b ON a.`id` = b.`id`;
      查詢結果:
      查詢最大條數:SELECT * FROM t_left_tab a LEFT JOIN t_right_tab b ON 1=1;
      查詢結果:
      3、總結
      A 數據庫左連接和右連接的區別:主表不一樣
      B 通過左連接和右連接,最小條數為3(記錄條數較小的記錄數),最大條數為12(3×4)

    posted @ 2014-07-17 09:51 順其自然EVO 閱讀(237) | 評論 (0)編輯 收藏

    Java 8中10個不易察覺的錯誤

    不小心重用了流
      我敢打賭,每人至少都會犯一次這樣的錯誤。就像現有的這些“流”(比如說InputStream),你也只能對它們消費一次。下面的代碼是無法工作的:
      IntStream stream = IntStream.of(1, 2);
      stream.forEach(System.out::println);
      // That was fun! Let's do it again!
      stream.forEach(System.out::println);
      你會碰到一個這樣的錯誤:
      java.lang.IllegalStateException:
      stream has already been operated upon or closed
      因此使用流的時候應當格外注意。它只能消費一次。
      不小心創建了一個”無限"流
      你可能一不留神就創建了一個無限流。就拿下面這個例子來說:
      IntStream.iterate(0, i -> i + 1)
      .forEach(System.out::println);
      流的問題就在于它有可能是無限的,如果你的確是這樣設計的話。唯一的問題就是,這并不是你真正想要的。因此,你得確保每次都給流提供一個適當的大小限制:
      // That's better
      IntStream.iterate(0, i -> i + 1)
      .limit(10)
      .forEach(System.out::println);
      不小心創建了一個“隱藏的”無限流
      這個話題是說不完的。你可能一不小心就真的創建了一個無限流。比如說下面的這個:
      IntStream.iterate(0, i -> ( i + 1 ) % 2)
      .distinct()
      .limit(10)
      .forEach(System.out::println);
      這樣做的結果是:
      我們生成了0和1的交替數列
      然后只保留不同的數值,比如說,一個0和一個1
      然后再將流的大小限制為10
      最后對流進行消費
      好吧,這個distinct()操作它并不知道iterate()所調用的這個函數生成的只有兩個不同的值。它覺得可能還會有別的值。因此它會不停地從流中消費新的值,而這個limit(10)永遠也不會被調用到。不幸的是,你的應用程序會崩掉。
      不小心創建了一個”隱藏”的并行無限流
      我還是想繼續提醒下你,你可能真的一不小心就消費了一個無限流。假設你認為distinct()操作是會并行執行的。那你可能會這么寫:
      IntStream.iterate(0, i -> ( i + 1 ) % 2)
      .parallel()
      .distinct()
      .limit(10)
      .forEach(System.out::println); 現在我們可以知道的是,這段代碼會一直執行下去。不過在前面那個例子中,你至少只消耗了機器上的一個CPU。而現在你可能會消耗四個,一個無限流的消費很可能就會消耗掉你整個系統的資源。這可相當不妙。這種情況下你可能得去重啟服務器了。看下我的筆記本在最終崩潰前是什么樣的:
      操作的順序
      為什么我一直在強調你可能一不小心就創建了一個無限流?很簡單。因為如果你把上面的這個流的limit()和distinct()操作的順序掉換一下,一切就都OK了。
      IntStream.iterate(0, i -> ( i + 1 ) % 2)
      .limit(10)
      .distinct()
      .forEach(System.out::println);
      現在則會輸出:
      0
      1
      為什么會這樣?因為我們先將無限流的大小限制為10個值,也就是(0 1 0 1 0 1 0 1 0 1),然后再在這個有限流上進行歸約,求出它所包含的不同值,(0,1)。
      當然了,這個在語義上就是錯誤的了。因為你實際上想要的是數據集的前10個不同值。沒有人會真的要先取10個隨機數,然后再求出它們的不同值的。
      如果你是來自SQL背景的話,你可能不會想到還有這個區別。就拿SQL Server 2012舉例來說,下面的兩個SQL語句是一樣的:
      -- Using TOP
      SELECT DISTINCT TOP 10 *
      FROM i
      ORDER BY ..
      -- Using FETCH
      SELECT *
      FROM i
      ORDER BY ..
      OFFSET 0 ROWS
      FETCH NEXT 10 ROWS ONLY
      因此,作為一名SQL用戶,你可能并不會注意到流操作順序的重要性。
      還是操作順序
      既然說到了SQL,如果你用的是MySQL或者PostgreSQL,你可能會經常用到LIMIT .. OFFSET子句。SQL里全是這種暗坑,這就是其中之一。正如SQL Server 2012中的語法所說明的那樣,OFFSET子名會優先執行。
      如果你將MySQL/PostgreSQL方言轉化成流的話,得到的結果很可能是錯的:
      IntStream.iterate(0, i -> i + 1)
      .limit(10) // LIMIT
      .skip(5)   // OFFSET
      .forEach(System.out::println);
      上面的代碼會輸出:
      5
      6
      7
      8
      9
      是的,它輸出9后就結束了,因為首先生效的是limit(),這樣會輸出(0 1 2 3 4 5 6 7 8 9)。其次才是skip(),它將流縮減為(5 6 7 8 9)。而這并不是你所想要的。
      警惕LIMIT .. OFFSET和OFFSET .. LIMIT的陷阱!
      使用過濾器來遍歷文件系統
      這個問題我們之前已經講過了。使用過濾器來遍歷文件系統是個不錯的方式:
      Files.walk(Paths.get("."))
      .filter(p -> !p.toFile().getName().startsWith("."))
      .forEach(System.out::println);
      看起來上面的這個流只是遍歷了所有的非隱藏目錄,也就是不以點號開始的那些目錄。不幸的是,你又犯了錯誤五和錯誤六了。walk()方法已經生成一個當前目錄下的所有子目錄的流。雖然是一個惰性流,但是也包含了所有的子路徑。現在的這個過濾器可以正確過濾掉所有名字以點號開始的那些目錄,也就是說結果流中不會包含.git或者.idea。不過路徑可能會是:..git\refs或者..idea\libraries。而這并不是你實際想要的。
      你可別為了解決問題而這么寫:
      Files.walk(Paths.get("."))
      .filter(p -> !p.toString().contains(File.separator + "."))
      .forEach(System.out::println);
      雖然這么寫的結果是對的,但是它會去遍歷整個子目錄結構樹,這會遞歸所有的隱藏目錄的子目錄。
      我猜你又得求助于老的JDK1.0中所提供的File.list()了。不過好消息是, FilenameFilter和FileFilter現在都是函數式接口了。
      修改流內部的集合
      當遍歷列表的時候,你不能在迭代的過程中同時去修改這個列表。這個在Java 8之前就是這樣的,不過在Java 8的流中則更為棘手。看下下面這個0到9的列表:
      // Of course, we create this list using streams:
      List<Integer> list =
      IntStream.range(0, 10)
      .boxed()
      .collect(toCollection(ArrayList::new));
      現在,假設下我們在消費流的時候同時去刪除元素:
      list.stream()
      // remove(Object), not remove(int)!
      .peek(list::remove)
      .forEach(System.out::println);
      有趣的是,其中的一些元素中可以的刪除的。你得到的輸出將會是這樣的:
      0
      2
      4
      6
      8
      null
      null
      null
      null
      null
      java.util.ConcurrentModificationException
      如果我們捕獲異常后再查看下這個列表,會發現一個很有趣的事情。得到的結果是:
      [1, 3, 5, 7, 9]
      所有的奇數都這樣。這是一個BUG嗎?不,這更像是一個特性。如果你看一下JDK的源碼,會發現在ArrayList.ArraListSpliterator里面有這么一段注釋:
      /* * If ArrayLists were immutable, or structurally immutable (no * adds, removes, etc), we could implement their spliterators * with Arrays.spliterator. Instead we detect as much * interference during traversal as practical without * sacrificing much performance. We rely primarily on * modCounts. These are not guaranteed to detect concurrency * violations, and are sometimes overly conservative about * within-thread interference, but detect enough problems to * be worthwhile in practice. To carry this out, we (1) lazily * initialize fence and expectedModCount until the latest * point that we need to commit to the state we are checking * against; thus improving precision. (This doesn't apply to * SubLists, that create spliterators with current non-lazy * values). (2) We perform only a single * ConcurrentModificationException check at the end of forEach * (the most performance-sensitive method). When using forEach * (as opposed to iterators), we can normally only detect * interference after actions, not before. Further * CME-triggering checks apply to all other possible * violations of assumptions for example null or too-small * elementData array given its size(), that could only have * occurred due to interference. This allows the inner loop * of forEach to run without any further checks, and * simplifies lambda-resolution. While this does entail a * number of checks, note that in the common case of * list.stream().forEach(a), no checks or other computation * occur anywhere other than inside forEach itself. The other * less-often-used methods cannot take advantage of most of * these streamlinings. */
      現在來看下如果我們對這個流排序后會是什么結果:
      list.stream()
      .sorted()
      .peek(list::remove)
      .forEach(System.out::println);
      輸出的結果看起來是我們想要的:
      0
      1
      2
      3
      4
      5
      6
      7
      8
      9
      而流消費完后的列表是空的:
      []
      也就是說所有的元素都正確地消費掉并刪除了。sorted()操作是一個“帶狀態的中間操作”,這意味著后續的操作不會再操作內部的那個集合了,而是在一個內部的狀態上進行操作。現在你可以安全地從列表里刪除元素了!
    不過,真的是嗎這樣?我們來試一下帶有parallel(), sorted()的刪除操作:
      list.stream()
      .sorted()
      .parallel()
      .peek(list::remove)
      .forEach(System.out::println);
      這個會輸出 :
      7
      6
      2
      5
      8
      4
      1
      0
      9
      3
      現在列表里包含:
      [8]
      唉呀。居然沒有刪完所有的元素?!誰能解決這個問題,我免費請他喝酒!
      這些行為看起來都是不確定的,我只能建議你在使用流的時候不要去修改它內部的數據集合。這樣做是沒用的。
      忘了去消費流
      你覺得下面這個流在做什么?
      IntStream.range(1, 5)
      .peek(System.out::println)
      .peek(i -> {
      if (i == 5)
      throw new RuntimeException("bang");
      });
      看完這段代碼,你覺得應該會輸出(1 2 3 4 5)然后拋出一個異常。不過并不是這樣。它什么也不會做。這個流并沒有被消費掉,它只是靜靜的待在那里。
      正如別的流API或者DSL那樣,你可能會忘了調用這個終止操作。當你使用peek()的時候也是這樣的,因為peek有點類似于forEach()。
      在jOOQ中也存在這樣的情況,如果你忘了去調用 execute()或者fetch():
      DSL.using(configuration)
      .update(TABLE)
      .set(TABLE.COL1, 1)
      .set(TABLE.COL2, "abc")
      .where(TABLE.ID.eq(3));
      杯具。忘了調用execute方法了。
      并行流死鎖
      終于快講完了~
      如果你沒有正確地進行同步的話,所有的并發系統都可能碰到死鎖。現實中的例子可能不那么明顯,不過如果你想自己創造一個場景的話倒是很容易。下面這個parallel()流肯定會造成死鎖:
      Object[] locks = { new Object(), new Object() };
      IntStream
      .range(1, 5)
      .parallel()
      .peek(Unchecked.intConsumer(i -> {
      synchronized (locks[i % locks.length]) {
      Thread.sleep(100);
      synchronized (locks[(i + 1) % locks.length]) {
      Thread.sleep(50);
      }
      }
      }))
      .forEach(System.out::println);
      注意這里Unchecked.intConsumer()的使用,它把IntConsumer接口轉化成了 org.jooq.lambda.fi.util.function.CheckedIntConsumer,這樣你才可以拋出已檢查異常。
      好吧。這下你的機器倒霉了。這些線程會一直阻塞下去:-)
      不過好消息就是,在Java里面要寫出一個這種教科書上的死鎖可不是那么容易。
      想進一步了解的話,可以看下Brian Goetz在StackOverflow上的一個回答。
      結論
      引入了流和函數式編程之后,我們開始會碰到許多新的難以發現的BUG。這些BUG很難避免,除非你見過并且還時刻保持警惕。你必須去考慮操作的順序,還得注意流是不是無限的。
      流是一個非常強大的工具,但也是一個首先得去熟練掌握的工具。

    posted @ 2014-07-17 09:49 順其自然EVO 閱讀(227) | 評論 (0)編輯 收藏

    QTP在webtable中查找指定字符

    ’ 首先獲取WebTable對象,然后通過ChildItem獲取指定單元格中的鏈接對象,并單擊該鏈接:
      ’ 獲取WebTable對象
      Set objTable = Browser("請登錄 博都網").Page("我的文章").WebTable("文章標題")
      intRow = 2
      intCol = 1
      ’ 通過ChildItem獲取單元格中的鏈接對象
      Set objLink = objTable.ChildItem(intRow, intCol, "Link" , 0)
      ’ 單擊鏈接
      objLink.click
      _______________________________________________
      ’獲取webtable的行數,并查找指定的內容
      numRows = Browser("請登錄 博都網_2").Page("我的文章").WebTable("文章標題").RowCount
      For i=2 to numRows
      title_text =Browser("請登錄 博都網_2").Page("我的文章").WebTable("文章標題").GetCellData(i,1)
      If trim(title_text) = trim(articleTitle)  Then
      reporter.ReportEvent 0,"測試成功","文章列表顯示新添加的文章標題"
      Exit For
      End If
      Next
      ’如果table有很多頁,數據不在第一頁,怎么查找?
      ’’’’’’’’’’’Function : 在webTable中查找元素’’’’’’’’’
      Function FindedItemInTable(pageObj1,WebTable_Obj1,searchStr,PageNum)
      ’ Finded :標記是否從table里找到數據
      ’ currentPage:當前頁;numRows:當前頁的行數
      Dim Finded,currentPage
      Finded = false
      ’從第一頁開始查找。
      For currentPage = 1 to PageNum
      ’==================初始化:保證從第一頁開始搜索==========================
      ’ If currentPage = 1 Then
      ’  pageObj.Link("pageLink").SetTOProperty "text",1
      ’  pageObj.Link("pageLink").SetTOProperty "href","javascript:forward(1)"
      ’  If  pageObj.Link("text:=1","href:=javascript:forward(1)").Exist(1) Then
      ’     pageObj.Link("text:=1").Click
      ’  End If
      ’ End If
     ’============================================
      If currentPage >1 Then
      pageObj.Link("pageLink").SetTOProperty "text",currentPage
      pageObj.Link("pageLink").SetTOProperty "href","javascript:forward("&currentPage&")"
      pageObj.Link("text:="&currentPage).Click
      pageObj.Sync
      msgbox  pageObj.GetROProperty("url")
      End If
      ’獲得當前頁的行數,開始逐行搜索
      numRows = WebTable_Obj.GetROProperty("rows")
      msgbox numRows
      For i=2 to numRows
      ItemStr =Cstr(WebTable_Obj.GetCellData(i,1))
      If trim(ItemStr) = trim(searchStr)  Then
      reporter.ReportEvent 0,"搜索成功","元素位于第"&currentPage&"頁,第"&i&"行"
      Finded = true
      Exit For
      End If
      Next
      ’找到了,退出
      If finded = true Then
      Exit For
      End If
      Next
      If finded = false Then
      msgbox "沒有找到數據!"
      End If

    posted @ 2014-07-17 09:43 順其自然EVO 閱讀(480) | 評論 (0)編輯 收藏

    測試自動化和準時交付直接的關聯

     在敏捷開發中, 我們都知道要將功能切割, 每次做些小功能, 然后持續交付價值給客戶.
      因此當你在開發每個小功能時, 你會不斷進行以下事情:
      1. 從主干 check out 程序代碼到分支
      2. 開發團隊在分支進行開發
      3. 小功能開發完后, 將分支程序, merge 回主干
      4. 在主干進行測試
      可是通常這樣在第四步時, 就會遇到一堆錯誤. 這是因為小功能還沒確認是否正確, 就和整個系統和起來測試, 將導致問題多多. 如果有很多小功能要放進來時, 這種情況就會更惡化.
      因此有些團隊可能會這樣做:
      1. 從主干 check out 程序代碼到分支
      2. 開發團隊在分支進行開發
      3. 開發完畢在分支進行測試
      4. 在分支測試通過, 將分支程序, merge 回主干
      5. 在主干再進行測試
      這樣做之后, 可以讓小功能測試比較穩定后, 再放到主干來. 可是遇到多個小功能同時開發時, 還是會遇到你進來的東西會跟別人不和, 導致整個系統無法運作.
      所以下一步你會在這樣改進:
      1. 從主干 check out 程序代碼到分支
      2. 開發團隊在分支進行開發
      3. 開發完畢在分支進行測試
      4. 把主干的程序 merge 到分支
      5. 把 merge 完后的分支程序進行測試
      6. 將 merge 完后的分支程序, 再 merge 回主干
      7. 在主干再進行測試
      因此你先確認小功能是否運作正常; 然后將主干的程序合并到分支后, 再確認是否正確; 最后合并到主干后, 在做一次確認是否都正常.
      看起來到目前為止, 應該考慮的很周到.
      可是... 有多少人這樣做呢? 似乎很少, 為什么正確的事情, 大家都不做呢?因為這樣反復進行的測試工作, 如果你沒有自動化, 你就會沒有空, 或者討厭去做這樣的事情, 導致大家就很少去做.
      有些人說沒問題, 我們會把測試自動化搞好, 這是小事. 于是他們就開始處理測試自動化的問題, 接著你又會發現到:
      要能自動產生 build, 否則每次手動要花多時間
      測試環境要自動準備好, 沒有干凈的環境, 測試結果可能會有影響
      每個小功能整合到主干后, 有可能之后出問題, 要重新回上個版本, 這個事情若是手動做, 也是件崩潰的事情
      ……
      所以再做下去, 你會發現整件事情沒有你想象的單純, 若是沒有落實 continuous integration 或是 continuous delivery, 你永遠沒有機會達到 agile 所說的, 每個 iteration 持續交付價值給客戶. 你所有的, 將會是至少落后一個 iteration 的交付. 因為在 agile 中, 每個 iteration 測試和開發要花的代價不同, 測試的代價是隨著 iteration 的進行, 逐漸高升.
      David: 老板,  agile 不是只是去上上 scrum 課就可以的.
      經理: 測試自動化我早就知道了, 所以 agile 根本沒有什么好學的啦
      David: …

    posted @ 2014-07-17 09:40 順其自然EVO 閱讀(158) | 評論 (0)編輯 收藏

    如何在需求不明確的情況下測試

     軟件生命周期中,需求是整個項目的源頭。俗話說良好的開端是成功的一半,但是,不是每個項目都能遵從流程,花太多時間在需求分析上,而把精力投入到代碼的編寫中。這可能導致什么問題呢?開發和測試對需求理解都不充分,開發出來的功能與實際需求不符,測試要么憑自己的經驗一步一步發掘潛藏的功能點,把項目往良性的軌道上引,要么就聽從開發的腳步,亦步亦趨。那么測試人員要如何在需求不明確或者文檔不全的情況下著手測試才能保證軟件的質量呢?
      一、參考同類型的網站:一般情況下,我們測的系統總會有原型可參考,比如我目前測的訂票系統,就可以參照攜程,主要功能基本一樣,細節可能有出入,攜程上操作一遍,然后再看看它提供的幫助,再有可以網上搜索資料,參考下行業的基礎知識,這都是收集需求的方法,這樣子下來也基本對訂票系統也就有個認識了,然后與開發經理確認,再和開發一起把功能定下來,該改的改,該修的修,BUG一點不含糊。弱弱的吐槽下,這個項目的開發居然都不知道有需求說明書,雖然寫的基本沒太大的價值。
      二、根據經驗和常識判斷:做項目多了就知道,萬變不離其宗,系統不一樣,思路可以套用,所謂的學以致用,舉一反三。我上個項目做的銀行測試,我照樣可以測現在的訂票系統,就在一個字:活。有需求照需求測,沒有需求找參照,說個例子吧,訂票系統中有個功能是積分,需求上就一句話提到有積分功能,怎么測?難道看到有這個功能就算過了?我后來就參照了淘寶的積分抵扣,下單了積分就被臨時凍結了,取消訂單又釋放出來,但開發在做這個功能的時候也沒有跟他們的頭溝通,直接是要等支付完成后才扣除積分,這導致一個什么問題呢,可以重復使用積分,如果真上線使用了,說不定會造成不小的經濟損失的。類似這樣的問題太多太多,你總可以從一些地方獲得參照,或者說是靈感,項目測的怎么樣,跟測試人員的素養有很大的關系,尤其是在沒有規范的流程下。
      三、溝通:毋庸置疑,這太重要了,需求不一定在文檔中寫出來,但道理上開發肯定知道需求的,但一般不會主動和測試溝通,因此,我們作為測試就要主動和開發人員溝通,不僅可以對系統有更深的了解,還可以對項目進度有把握。
      四、多和同事討論

    posted @ 2014-07-17 09:38 順其自然EVO 閱讀(230) | 評論 (0)編輯 收藏

    電子商務網站測試經驗總結

    從業電子商務網站測試一年多,很久沒有進行測試的經驗方面的總結了,今天對之前測試的電子商務網站進行了一次總結,總體按照兩種模式進行劃分總結:1.按照測試類型    2.按照電子商務網站的系統架構
      1.按照測試類型來劃分
      1.兼容性
      1.1主要是在瀏覽器兼容(360瀏覽器IE6 IE8瀏覽器)
      12.操作系統,主要體現在操作系統兼容(xp win2003 win2007)
      2.UI測試
      2.1檢查連接是否正確
      2.2是否有文字錯誤信息
      2.2產品價格是否有顯示錯誤。
      3.用戶體驗測試UE
      3.1首頁產品的展示與分類
      3.2搜索結果頁,搜索結果的正確性,和結果頁面信息的展示
      3.3產品詳情頁。產品介紹頁面將對客戶的購買行為起到關鍵的作用,產品圖片,文字說明,產品描述就相當于柜臺服務員與產品說明書。
      4.購物流程及購物規則測試
      4.1B2C網站最重要的流程就是購物流程,包括幾個重要功能:購物車、配送方式、支付方式、提交訂單。這一流程的用戶體驗的重要性在于讓客戶能很容易的完成下單的過程
      測試產品能否放入購物車中
      4.2當某種產品有購物數量限制時,超過這一數值,能否也能放入購物車中
      4.3購物車中的購物限制是否正確
      4.4積分是否能夠兌換正品,或者限購的產品
      4.5積分是否能夠兌換促銷類的產品。
      5.支付流程
      5.1購物車中的產品能否正常支付
      5.2當支付完成,不等頁面跳轉,直接關閉瀏覽器,數據傳遞是否正確
      5.3當支付完成,等待頁面跳轉,跳轉到得頁面是否正確
      5.4網站某個模塊間的數據傳遞是否正確
      6.訂單流程測試
      6.1訂單提交完后,對訂單的處理流程的驗證,以及相應的訂單狀態核對是否正確。
      7.性能,響應速度測試。
      7.1并發性測試如秒殺功能、
      7.2同時購買同一個限定產品
      7.3相同的帳號進行2次積分兌換產品的并發操作。
      7.4提交訂單時,并發操作時是否存在多個訂單。
    重點:
      在進行測試時,首先需要清楚應用系統的輸入流,數據流的情況,在基本功能通過的情況下,才能進行其它的類型的測試。
      電子商務網站測試應該關注:
      1.業務流和數據流
      2.重點在用戶體驗測試方面吧
      3.還有安全和性能方面的。web的cookies測試也是重點。
      2.按照電子商務網站的系統架構
      1典型系統結構(目前都是采用的三層C/S架構,即1.表示層,2.業務層,和3.數據層(頁面與數據庫交互的)。層)。
      1.表示層(測試檢查應用程序的前端是否正確)
      1.1內容測試(檢查web應用系統提供的信息,正確性,準確性,相關的操作元素是否正確等)。
      1.2web站點結構(檢查web站點結構上存在的錯誤,發現無效的連接)
      包含三個方面:
      1.是否存在空連接地址  2.是否連接到指定的頁面3.是否存在連接報錯。
      1.3用戶環境(瀏覽器兼容操作系統兼容)
      2.業務邏輯層(業務邏輯層主要是為了發現業務邏輯中存在的問題)。
      2.1性能測試(負載測試是為了測量Web系統在某一負載級別上的性能,以保證Web系統在需求范圍內能正常工作).
      2.2數據驗證。測試用戶采集的數據,通常都是以表單的形式。比如說用戶注冊(必須保證用戶的數據一致性,正確性,完整性)才能進行提交。然后到數據庫表中去進行驗證。
      2.3業務測試。測試系統的業務處理過程的正確性,電子商務系統必須在全部的時間里正確處理業務,無一例外。因此,要通過測試確保業務處理的正確性。如(如,購物,加入購物車,結算,提交訂單,訂單處理流程)的一個過程。
      3 數據層。(數據層的測試,主要是指對應系統用于儲存和獲取信息的數據庫管理系統的測試)
      3.1響應時間,定量并發操作,對應用系統是否造成響應數據的方面的影響。直接影響用戶體驗。
      3.2數據完整性(主要驗證表單數據的提交及存儲),也就是數據完整性測試。將提交的數據
      與數據庫中提交的數據進行比對,確認是否正確。

    posted @ 2014-07-17 09:35 順其自然EVO 閱讀(239) | 評論 (0)編輯 收藏

    僅列出標題
    共394頁: First 上一頁 82 83 84 85 86 87 88 89 90 下一頁 Last 
    <2025年5月>
    27282930123
    45678910
    11121314151617
    18192021222324
    25262728293031
    1234567

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 亚洲色无码专区一区| a级毛片免费网站| 亚洲v国产v天堂a无码久久| 国产做国产爱免费视频| 亚洲狠狠狠一区二区三区| 国产精品嫩草影院免费| 国产一精品一AV一免费| 亚洲精品色播一区二区| 一级女性全黄久久生活片免费 | 91网站免费观看| 黄色a三级三级三级免费看| 亚洲高清无在码在线无弹窗| 男女啪啪永久免费观看网站| 国产色无码精品视频免费| 亚洲校园春色另类激情| 亚洲伊人久久精品影院| 久久久精品视频免费观看| 亚洲youjizz| 久久亚洲综合色一区二区三区| 在线免费观看中文字幕| 91福利免费视频| 一区二区三区免费看| 伊人婷婷综合缴情亚洲五月| 免费看美女裸露无档网站| 久青草视频在线观看免费| 亚洲精品永久在线观看| 亚洲尹人香蕉网在线视颅| 亚洲精品黄色视频在线观看免费资源 | 亚洲日韩乱码中文字幕| 亚洲爆乳无码专区| 亚洲国产小视频精品久久久三级 | 亚洲成人在线网站| 亚洲日韩在线第一页| 丁香花在线观看免费观看 | 国产va在线观看免费| 欧亚一级毛片免费看| 亚洲欧洲国产综合AV无码久久| 久久综合亚洲鲁鲁五月天| 亚洲中文字幕无码日韩| 亚洲国产精品碰碰| 夭天干天天做天天免费看|