<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/

    單元測試等價于白箱測試嗎?

      單元測試 = 白箱測試? 這是很多人的想法. 一聽到白箱測試, 就認為他就是單元測試. 或者認為單元測試時, 就是要用白箱測試的方法來進行.
      事情是這樣嗎? 讓我們繼續看下去:
      當我們要測試這個程序時
      Stack push(Stack s, int key)
      你會怎么測試呢? 你可能會考慮以下幾種狀況
      (1) 空的 stack, 第一次 push
      (2) 不是空的 stack, 然后 push 東西
      (3) stack 是滿的, push 個東西看會不會有問題
      (4) 不是空的 stack, 然后 push 一個字符
      (5) 不是空的 stack, 然后 push 一個指標
      你所做的大多是根據程序思考邏輯, 或者是根據輸入的值域來做參考, 來建立測試個案.
      這些方式其實都是黑箱測試(用到了 use case testing 和 Equivalence Class Testing等方法, 可自行去網絡上找詳細介紹), 也就是不管程序內部如何被實作. 只根據行為和輸入值域來開立測試.
      那真正的白箱測試會是怎么進行呢?
      基本上, 可以測試的狀況有無限多種. 而白箱測試是要根據程序內容來決定要怎樣挑最小可測試的集合.
      那程序內有甚么東西, 可以讓我們來做挑選的判斷呢? 一般常見的是根據程控邏輯. 例如: 是否經過所有的敘述(statement); 是否經過程序所有分支等等.
      如果以經過所有的敘述為例, 對于下面的程序
      01: Stack push(Stack s, int key)
      02: {
      03:     if(isFull(s)){
      04:        printf("Stack is full !!\n");
      05:     }else{
      06:         s.top = s.top + 1;
      07:         s.element[s.top] = key;
      08:         printf("Success push %d in the Stack\n", key);
      09:     }
      10:     return s;
      11: }
    你會找出這組路徑, 來當作最小需要測試的集合, 然后對它建立其相對應的測試個案
      path1: 01-02-03-05-06-07-08-09-10-11
      test case 1:
      push (s, 3)
      path2: 01-02-03-04-10-11
      test case 2:
      push (s, 3) (repeat 10 times, 如果 stack 大小是10 的話)
      push (s, 3)
      (當然你可以只用test case 2, 因為它涵蓋了 test case 1 的狀況)
      一般人通常不會先分析執行路徑, 再找測試個案. 大多是根據一些準則, 找出測試個案就開始測試了. 所以一般單元測試是用黑箱測試方式在進行, 而非白箱測試.
      那為何大家會有錯覺單元測試 = 白箱測試呢?
      那 是因為在進行白箱測試時, 對于一個大的系統要找出可執行路徑, 會是一件很復雜的事情. 但是對于每個單元時, 這件事情變得比較容易, 比較有可能不藉由工具的輔助, 就能自己進行. 也就是說在單元測試時, 比較容易進行白箱測試. 可是不知怎么傳的, 很多人就把這兩個視為同義.

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

    好的黑盒測試方法應該是什么?

      很多測試人員會詢問, 是否有一種測試方法, 可以很系統化地, 來開立所有測試個案.
      我也很期待有這種東西, 可惜一直沒有看到, 不管哪種黑盒測試方法, 都有它的優點和缺點.
      更重要的是黑盒測試有個重大的致命點, 它是完全依賴測試人員的經驗. 如果測試人員的產品領域知識, 以及產品所處的系統知識豐富, 就能開出更好的測試個案.
      例如: 等價分析法(Equivalence Class). 他要求先找出等價區域 (Partition or equivalence class),  然后對每個區域開出一個測試個案, 只要這些個案執行完, 就說測試完畢.
      但是有經驗的測試人員, 他能找出的區域, 可能質量比沒有經驗的人好上百倍. 所以不管測試方法再好, 也需要有優秀的人才. 就像圓月彎刀中, 丁鵬殺了柳若松后說, "有些人縱有神刀在手, 仍是無法成為刀中之神的”.  資質永遠是第一首選.
      可是如果資質不好, 就沒有辦法改變了?
      在一次對話中, 讓我被啟發了. 或許這些方法無法讓你開出很完整的測試個案, 但是是否有方法, 讓你清楚表達你的思考邏輯.  如果可以清楚表示, 別人或是自己就可以容易檢查有沒有缺陷或是遺漏.
      就這像用魚骨圖, mindmap, 或是 decision tree 等方式來呈現事情, 可以讓別人看到后很快可以理解, 并且也可以很快地給你回饋. 所以同理, 好的黑盒測試方法, 應該也要具備相同的特質.
      因此根據這樣的想法, 哪一種黑盒測試的方法比較合適呢? 目前看起來應該是 Decision Table Testing. 因為它會將你想的測試狀況, 明確清楚的列出來, 這時候別人就可以檢視你的思考邏輯. 以下是使用 decision table 測試方法的范例: 說明在這樣的商業規則下, 你需要考慮哪些測試 scenario. 這樣的表達方式, 別人可以快速知道你是怎么思考, 是否有不足的地方.
      所以我現在從找最好的測試方法, 改成找最容易表達你測試思維的方法. 這算是進步呢? 還是我很容易滿足 ….

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

    自己實現的附帶文件的壓力測試方法

    前段時間做了一個服務器端接口,是附帶文件上傳的;后來我們要對這個接口進行壓力測試
      其實很多現成的方式可以做壓力測試,但是附帶文件的的壓力測試缺不怎么符合我的需求,jmeter是可以做附帶文件上傳的壓力測試的,只是它是圖形界面,而我目前的需求是要在測試機器上面去跑測試,而測試服務器是不能帶圖形界面的,所以jmeter的方案否決掉;
      apache ab test,也是一個壓力測試的好工具,只是研究了好久老搞不掂怎么做附帶文件上傳的壓力測試(備注:在本文的最后我附帶一下我研究的結果,說多了都是淚)
      好了,現在我說下我自己的這個測試工具:
      它依賴于賴于httpclient相關的包,包括:commons-codec-1.6.jar、commons-logging-1.1.3.jar、fluent-hc-4.3.4.jar、httpclient-4.3.4.jar、httpclient-cache-4.3.4.jar、httpcore-4.3.2.jar、httpmime-4.3.4.jar、httpmime-4.3.4.jar;
      大家可以到apache的官方網站:http://hc.apache.org/downloads.cgi  去下載相關的包;
    import java.io.File;
    import java.io.IOException;
    import java.util.concurrent.ExecutorService;
    import java.util.concurrent.Executors;
    import java.util.concurrent.atomic.AtomicInteger;
    import org.apache.http.HttpEntity;
    import org.apache.http.client.methods.CloseableHttpResponse;
    import org.apache.http.client.methods.HttpPost;
    import org.apache.http.entity.ContentType;
    import org.apache.http.entity.mime.MultipartEntityBuilder;
    import org.apache.http.entity.mime.content.FileBody;
    import org.apache.http.entity.mime.content.StringBody;
    import org.apache.http.impl.client.CloseableHttpClient;
    import org.apache.http.impl.client.HttpClients;
    import org.apache.http.util.EntityUtils;
    public class ClientMultipartFormPostTest {
    private static ExecutorService pool = Executors.newFixedThreadPool(300);
    public static void main(String[] args) throws Exception {
    final String path = args[0];//文件地址
    final String url = args[1]; //調用的URL
    final int i_len = Integer.parseInt(args[2]);//線程總數
    final int j_len = Integer.parseInt(args[3]);//每個線程的請求數(暫時沒用到)
    final AtomicInteger c = new AtomicInteger(0);
    final long s = System.currentTimeMillis();
    for (int i = 0; i < i_len; i++) {
    new Thread(new Runnable() {
    @Override
    public void run() {
    while (true) {
    try {
    upLoadLogMultiThread(url,path);
    int cc = c.addAndGet(1);
    if (cc % 1000 == 0) {
    System.out.println(String.format("c: %d, t: %d", cc, (System.currentTimeMillis() - s)));
    }
    } catch (IOException e) {
    // TODO Auto-generated catch block
    e.printStackTrace();
    }
    }
    }
    }).start();
    }
    }
    public static void upLoadLogMultiThread(String url,String path) throws IOException{
    CloseableHttpClient httpclient = HttpClients.createDefault();
    try {
    HttpPost httppost = new HttpPost(url);
    FileBody bin = new FileBody(new File(path));
    StringBody comment = new StringBody("A binary file of some kind", ContentType.TEXT_PLAIN);
    HttpEntity reqEntity = MultipartEntityBuilder.create()
    .addPart("bin", bin)
    .addPart("comment", comment)
    .build();
    httppost.setEntity(reqEntity);
    CloseableHttpResponse response = httpclient.execute(httppost);
    try {
    HttpEntity resEntity = response.getEntity();
    EntityUtils.consume(resEntity);
    } finally {
    response.close();
    }
    } finally {
    httpclient.close();
    }
    }
    }
     測試結果,如圖所示:
      我們程序的邏輯是每請求1000次,打印一次;
      上面的結果翻譯的結果就是:
      1----請求1000次,耗費時間為3727毫秒;
      1----請求2000次,耗費時間為6253毫秒;
      1----請求3000次,耗費時間為8713毫秒;
      1----請求4000次,耗費時間為11028毫秒;
      1----請求5000次,耗費時間為13340毫秒;
      …
      依據上面的結果,我們可以做個預估:每秒可以承受的4000次請求;也就是說我們可以大大預估一天有3千萬次請求數,這個程序都是可以應付對的;
      但是上面的結論并沒說明文件,考慮到并發用戶的情況,好!那我們分1個并發,10個并發,100個并發,1000個并發,(我的并發是以線程來區分級別,估計大多數測試工具也是以這樣的一種方式去區分,備注:線程并非同一時刻,據本人了解,線程的區分度大概納秒級別的,還是在同一個進程里面去處理;而進程是可以利用上多核CPU的,舉例:4個核的CPU,開4個進程是可以時刻并行的運行,也就是說這4個進程是同一時刻在跑。)
      10線程并發:
      也就是說10個并非,每秒執行9千+;
      100個線程并非:
      也就是說100并非,每秒執行1.5萬次;
      1000個并非:
      已經掛掉了,也就是說這個小的后端程序能夠承受的并非級別是100~1000之間(一臺主機的情況,如果是集群的話,100萬臺服務器的話,相當于并發在1億~10億之間,如果按照業界傳聞facebook的幾十萬臺,Google級百萬臺,在還沒考慮主機CPU、內存的這個測試結果是非常可觀,目前主機是雙核2G內存的主機);
      測試方法就是:java -jar errlogClient.jar path url n c
      各個參數的標識:path = 目標文件路徑 ; url = 請求的地址 ; n = 線程總數 ; c = 每個線程調用請求的次數(備注目前上面的程序我是做循環跑的,所以暫時沒用上,大家覺得如果需要用上的話可以改改上面的程序)
      這個工具如果大家覺得還湊合用的話就盡管拿去用吧~

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

    linux打包壓縮命令匯總

         摘要: tar命令 [root@linux ~]# tar [-cxtzjvfpPN] 文件與目錄 ....參數:-c :建立一個壓縮文件的參數指令(create 的意思);-x :解開一個壓縮文件的參數指令!-t :查看 tarfile 里面的文件!特別注意,在參數的下達中, c/x/t 僅能存在一個!不可同時存在!因為不可能同時壓縮與解壓縮。-z :是否同時具有 gzip 的屬性?亦即是否需...  閱讀全文

    posted @ 2014-07-22 10:08 順其自然EVO 閱讀(164) | 評論 (0)編輯 收藏

    深入理解Linux操作系統守護進程的意義

         摘要: Linux服務器在啟動時需要啟動很多系統服務,它們向本地和網絡用戶提供了Linux的系統功能接口,直接面向應用程序和用戶。提供這些服務的程序是由運行在后臺的守護進程(daemons)來執行的。守護進程是生存期長的一種進程。它們獨立于控制終端并且周期性的執行某種任務或等待處理某些發生的事件。他們常常在系統引導裝入時啟動,在系統關閉時終止。linux系統有很多守護進程,大多數服務器都是用守護進程實現的...  閱讀全文

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

    NoSql數據庫初探-mongoDB環境搭建

    NoSQL數據庫一改關系型數據庫的缺點,更容易的集成、分布式、無模式、故障恢復等特點,正在一步步餐食關系型數據庫的市場,作為一個與時俱進的碼農了解一下新技術是必須的,尤其是在讀了《NoSql精粹》之后,更是想體驗一下NoSql數據庫的威力。
      MongoDB是一種文檔數據庫,也就是說對于領域模型中的每一個聚合來講,都會作為一個文檔來存儲。
      MongoDB有如下優點:
      面向文檔存儲、全索引支持、同步機制和高訪問性、自動分片、查詢、靈活的聚集和數據處理、映射化簡、文件存儲。
      第一步:安裝
      從版本2.2開始,mongoDB就不支持XP操作系統了,蛋疼,現在我就在用XP,看來只能用2.2之前的版本了,
      可用的版本只有一個2.0.9,我已經共享到百度網盤了,下載地址:http://pan.baidu.com/s/1i3GEs1v,如果下載地址失效了,請去官網下載。
      第二步:設置數據庫環境并啟動數據庫
      將壓縮版解壓之后放到任意一個硬盤上,比如我就放到了E:\mongodb-win32-i386-2.0.9
      先創建一個存放文檔文件的文件夾,E:\mongodb-win32-i386-2.0.9\data此文件夾是用來存放數據文檔的
      創建完成之后,將此文件夾配置到mongoDB,讓mongoDB將數據存放到此文件夾。
      配置并啟動數據庫:
      運行命令行:E:\mongodb-win32-i386-2.0.9\bin\mongod.exe --dbpath E:\mongodb-win32-i386-2.0.9\data
      (如果沒有指定,mongoDB啟動時默認在路徑C:\data下存放數據文檔)
      第三步:
      數據庫啟動之后,我們就可以連接數據庫進行訪問并存儲數據了
      另起一個命令窗口并運行:E:\mongodb-win32-i386-2.0.9\bin\mongo.exe --dbpath E:\mongodb-win32-i386-2.0.9\data
      后面的參數是要連接到的數據目錄
      默認情況下mongoDB會選中一個名叫test的數據庫,如果不知道當前所處的數據庫,可以運行db命令來查看
      查看所有的數據庫:
      show dbs
      切換數據庫:
      use mydb
      如果此時切換的數據庫不存在,沒關系,只要不向該數據庫存放數據,mongoDB是不會在硬盤上創建該數據庫的。
      是該存放數據的時候了,先說一下mongoDB中的一些概念。
      mongoDB中有db、collection、document,db就對應關系數據庫中的數據庫,而collection則對應了關系型數據庫中的表,而document就對應了關系型數據庫表中的一行數據。mongoDB中的文檔就像一個json文件一樣,我們可以將一個javascript中的對象字面量創建為一個document,如通過如下方式定義了兩個對象變量:
      j = { name : "mongo" }
      k = { x : 3 }
      將j和k這兩個文檔存入名為“testData”的collection中
      1
      2
      db.testData.insert( j )
      db.testData.insert( k )
      前面已經說過了,db為當前所處的數據庫對象,而testData是一個collection,此時還沒有對應的collection,當insert執行完畢之后,就創建了collection對象
      我們可以通過
      show collections
      命令來查看當前數據庫中所有的collection
      此時會返回testData和 system.indexes, system.indexes是mongoDB自己提供的collection,不用管它
      我們可以通過如下語句查詢testData中的所有的數據
      db.testData.find()

    此時的find方法會返回一個游標對象
      因為此時并沒有一個變量接收該游標對象,所以會默認至多打印出20條數據(當然只會打印剛剛的那兩條數據,因為我們的testData中只有這兩條)
      { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
      { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
      _id屬性是mongoDB自動生成的,因為每個文檔都要有一個“主鍵”(跟關系型數據庫中主鍵很像),而此時我們并沒有提供_id。
      我們來試著添加更多的數據:
      在命令行中輸入:
      for (var i = 1; i <= 25; i++) db.testData.insert( { x : i } )
      一個for循環,循環插入了25條數據
      我們再執行一下
      db.testData.find()
      結果輸出

    { "_id" : ObjectId("4c2209f9f3924d31102bd84a"), "name" : "mongo" }
    { "_id" : ObjectId("4c2209fef3924d31102bd84b"), "x" : 3 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990be6"), "x" : 1 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990be7"), "x" : 2 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990be8"), "x" : 3 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990be9"), "x" : 4 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bea"), "x" : 5 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990beb"), "x" : 6 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bec"), "x" : 7 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bed"), "x" : 8 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bee"), "x" : 9 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bef"), "x" : 10 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf0"), "x" : 11 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf1"), "x" : 12 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf2"), "x" : 13 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf3"), "x" : 14 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf4"), "x" : 15 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf5"), "x" : 16 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf6"), "x" : 17 }
    { "_id" : ObjectId("51a7dc7b2cacf40b79990bf7"), "x" : 18 }
    has more

      只輸出了20條數據
      后面還有has more提示后面還有數據
      再在命令行中輸入it會輸出下一批20條數據
      如何才能將數據全部輸出呢?
      此時我們用一個變量來接收游標:
      var c = db.testData.find()
      c就是游標對象
      此時我們通過for循環將全部數據輸出:
      while ( c.hasNext() ) printjson( c.next() )
      printjson方法將文檔以json的格式輸出
      游標對象的hasNext方法用來判斷是否還有下一個文檔,而next方法用來獲取下一個文檔。
      如果我們只想獲取第5個文檔,該怎么辦呢?
      當然可以在遍歷游標的時候對遍歷過的文檔計數,并將第5個文檔輸出即可,但是這種方式確實是有點啰嗦了。
      我們此時可以在游標對象上直接添加一個下標即可,如:
      printjson( c [ 4 ] )
      此時輸出了第5個文檔
      { "_id" : ObjectId("51a7dc7b2cacf40b79990bea"), "x" : 5 }
      但是此時請注意:
      c [ 4 ]方法會將所有該collection下的文檔讀取進內存,這相當于在游標上執行了cursor.toArray() 方法,
      此方法將所有的文檔加載到了內存中,然后再在返回的數組中查找索引值是4的文檔,所以游標下標方法應慎用啊
      如果我們想查詢a是18的那個document該怎么辦呢?
      此時我們還可以借助find方法,但是此時要給find方法提供一個模板文檔
      一個模板文檔詳細描述了查詢策略,如:db.testData.find( { x : 18 } )
      此時的{x:18}就是一個模板文檔,是指查詢文檔時只保留x為18的文檔。
      查詢結果如下:
      { "_id" : ObjectId("51a7dc7b2cacf40b79990bf7"), "x" : 18 }
      不要忘了,find方法返回一個游標對象,只不過此時的查詢只有一個文檔符合條件。
      如果只想返回一個文檔,而不是游標對象,可以使用findOne方法,findOne方法返回一個文檔對象,不管符合條件的文檔有多少個,它只返回第一個。
      如果想對返回的文檔數目進行限制,可以在游標上調用limit方法,如下:
      db.testData.find().limit(3)
      只會返回前3個文檔
      結果如下:
      { "_id" : ObjectId("51a7dc7b2cacf40b79990be6"), "x" : 1 }
      { "_id" : ObjectId("51a7dc7b2cacf40b79990be7"), "x" : 2 }
      { "_id" : ObjectId("51a7dc7b2cacf40b79990be8"), "x" : 3 }

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

    Java中的HashMap淺析

     在Java的集合框架中,HashSet,HashMap是用的比較多的一種,順序結構的ArrayList、LinkedList這種也比較多,而像那幾個線程同步的容器就用的比較少,像Vector和HashTable,因為這兩個線程同步的容器已經不被JDK推薦使用了,這是個比較老式的線程安全的容器,JDK比較推薦的是采用Collections里面的關于線程同步的方法。
        問題來源:
        1.為什么要有HashMap?
        《Thinking In Java》里面有一個自己采用二維數組實現的保存key-value的demo,書上也說到性能問題,因為從數據結構的順序結構的觀點來看,常規的線性存儲,你弱需要找到其中的某個元素,就需要遍歷這個鏈表或者數組,而遍歷的同時需要讓鏈表中的每一個元素都和目標元素做比較,相等才返回,Java里面用equals或者==。這對性能是毀滅性的傷害。
        2.HashMap的優勢是什么?
        Hash算法就是根據某個算法將一系列目標對象轉換成地址,當要獲取某個元素的時候,只需要將目標對象做相應的運算獲得地址,直接獲取。
        3.Java中的Hash?
        事實上Java的數據無非就三種,基本類型,引用類型(類似C里面的指針類型)和數組,有些地方說是2種類型,只有引用類型和數組。通過這三種數據類型可以構建出任何數據結構。在Java中,ArrayList這種底層就是用Objec數組來構建的,而HashMap也是用數組來構建,只不過數據數組的數據類型是一個叫做Entry的內部類來保存key、value、hash(不是hashCode)和next(也就是鏈表的下一個元素)。其實HashSet也是HashMap,只不過比較特殊,沒有使用Entry的value而只用了key而已。看看HashSet的構造方法:
        public HashSet() {
        map = new HashMap<E,Object>();
        }
        所以從這個意義上來講就沒必要討論HashSet了,他只不過是特殊的HashMap而已。
        HashMap詳解:
        基調:由于通過hash算法產生的邏輯地址可能導致沖突,所以對于一個長度為length的數組,里面存放小于length個數據元素的時候就有可能出現沖突的現象,因為比如說要在長度為16的數組中存放字符串(也就是一個空的HashMap默認的長度),每個字符串通過調用自身的hashCode()方法會得到該字符串的hashCode,然后通過HashMap的這兩個方法會算出在數組中的位置,也就是下面的 i。
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        任意字符串的hashCode通過上面2個方法都會得到一個i,這個i就是在數組中的位置,這里比較巧妙的設計就是indexFor(hash,table.length)這個方法:
        static int indexFor(int h, int length) {
        return h & (length-1);
        }
        這個方法里面的任意h與(length-1)做位運算之后得到的值始終都是在length之內的,也就是在數組table之內,因為拿任意一個數來和另一個數來做與運算,結果肯定是小于等于較小的哪一個數,我以前第一次看到這就比較震驚,為什么那些人能想出這么巧妙的計算在table中的位置的方法。與此同時,既然字符串調用hashCode()會得到一個值,那么就會出現不相同的字符串調用hashCode方法之后得到的值是一樣的,這種可能性是存在的,而且幾乎肯定是存在的。這時候就需要在數組的某個位置增加一個鏈表結構,用戶存儲相同的hashCode的字符串,而這個時候HashMap的size同樣也會自增1,盡管這2個字符串只有一個存在于數組中。HashMap中的size變量有兩個作用,第一是通過調用size()方法來返回map的長度,
        public int size() {
        return size;
        }
        第二個作用相當重要,就是解決hash算法的核心力量,解決沖突。在HashMap的構造方法中可以看出,hashmap的長度和底層數組table都是capacity,但是還有一個變量叫做threshold,極限值,閾值的意思,默認情況的構造方法:
        public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
        }
    這個閾值就是數組長度和加載因子的乘積,這東西有什么用呢,假設都按照默認情況來看,默認構造方法構造出來的hashmap長度為16,底層數組長度也為16,而閾值
        threshold長度為12,因為默認加載因子是0.75。也就是說當箱map中存放12個元素是,map的結構沒什么變化,但是當存儲第13個的時候,table就需要擴容了,擴大為原來的2倍。這時候是什么結局呢,如果加載因子是1,那么map中存放16個的時候他是不會擴容的,table.length = 16,而為0.75的時候存放16個數據的時候table.length = 32。那么同樣是存放16個數據,分別在長度為16的數組和32的數組中存放,出現沖突的幾率一般來說16的數組要大一些,那為什么會大一些呢,因為某個數據存放進入數組的位置是根據
        int hash = hash(key.hashCode());
        int i = indexFor(hash, table.length);
        這兩個方法算出來的,其中就包括table.length,換句話說,位置i跟hash和table.length是相關的,也就是說位置i與table.length是聯動的,換個角度,存放的16個數據假設是固定的,而得出hashCode的算法也是固定的,那么位置i就只跟length的大小有關聯了,一般來說length越大,數據的沖突幾率就低一些,在map.getValue(key)的時候需要在鏈表中比較的次數就少一些,性能就高一些。這就是Java中hashmap的性能因素,一般來說加載因子factor大,同樣個數的數據所占用空間就越小,table.length就越小,沖突幾率就越大,反之空間利用率低,性能高,類比一下,比如你地上放了10個碗,你手里面握了10顆大米,你撒下去,前提是必須10顆米都要撒進碗里,你是不是會發現有些碗里面裝了兩顆三顆,而有些碗是空的,接下來,你在地上擺20個碗,還是撒10顆米下去,依然是所有的米都要進碗,依然還是會出現有些晚是空的,有些是一顆兩顆三顆這種現象,但是很明顯一般來講20個碗的時候每個碗里面裝不止一顆的情況要比10個碗的情況要少,當然也不一定完全是這樣,但是一般來說是這樣,這就是hash算法,如果設計的好的情況下我們希望每個碗里面都最多放一顆進去,但是這種情況比較少見,但不管怎么說,按照普遍情況來看,20個碗的裝多顆的情況是比10個碗裝多顆的情況要少一點。從數據結構的角度來說叫做用空間換時間的策略,以空間換時間何止hash算法,雙向鏈表也是用空間換時間的策略。至于說為什么默認是0.75,我估計這個是前輩們和科學家們總結出來的一個這種的辦法,空間利用率比較不錯的同時性能比較令人接受吧。
        順便說一下啊,當我們不斷的往一個hashmap里面添加數據的時候,如果超過某個閾值,他就會擴容,擴容的同時會讓之前的所有元素重新生成地址,并且把原來的數組里面的數據遷移到新的數組中(新的數組容量是原來的兩倍長度)。順便說下,這個數據遷移其實對性能損耗還是相當大的,畢竟你是要復制數組,同時要重新構建每個元素的在table中的位置,因此我們可以在使用hashMap之前大概的估算一下這個hashMap里面大概會存多少個元素,這樣就可以在new hashmap的時候就給定他的容量,這樣數據遷移的次數相對就少一些,性能就更好一點。
        接下來從JDK的源碼來看看HashMap。
        1.構造出一個空的HashMap。默認長度16,底層Entry數組也是16的默認長度。默認加載因子default_factor為0.75。閾值16*0.75=12。key和value都存在與Entry這個類型里面。
        public HashMap() {
        this.loadFactor = DEFAULT_LOAD_FACTOR;
        threshold = (int)(DEFAULT_INITIAL_CAPACITY * DEFAULT_LOAD_FACTOR);
        table = new Entry[DEFAULT_INITIAL_CAPACITY];
        init();
        }
        2.調用put方法。
    public V put(K key, V value) {
    if (key == null)
    return putForNullKey(value);
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
    Object k;
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
    V oldValue = e.value;
    e.value = value;
    e.recordAccess(this);
    return oldValue;
    }
    }

        首先是判斷key是否為空,如果為空,那么調用下面這個方法,這個方法說明,HashMap的null的key始終是存放在table的table[0]位置的,不管table[0]位置有沒有沖突都是這樣。
    private V putForNullKey(V value) {
    for (Entry<K,V> e = table[0]; e != null; e = e.next) {
    if (e.key == null) {
    V oldValue = e.value;
    e.value = value;
    e.recordAccess(this);
    return oldValue;
    }
    }
    modCount++;
    addEntry(0, null, value, 0);
    return null;
    }

        如果不為空,那么繼續,這里,如果算出來的位置i出已經有元素了,說明沖突了,那么遍歷沖突鏈表,如果發現key相等,那么直接用新的value替換掉就的value并且返回舊的value。這里只判斷相等的情況而不判斷不相等的情況,也就是這里不做添加操作。
    int hash = hash(key.hashCode());
    int i = indexFor(hash, table.length);
    for (Entry<K,V> e = table[i]; e != null; e = e.next) {
    Object k;
    if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
    V oldValue = e.value;
    e.value = value;
    e.recordAccess(this);
    return oldValue;
    }
    }

        接下來,上面的步驟說明,新添加的數據在位置i處不是key相等的情況,就真正的添加數據了。調用addEntry(hash, key, value, i)方法。
        void addEntry(int hash, K key, V value, int bucketIndex) {
        Entry<K,V> e = table[bucketIndex];
        table[bucketIndex] = new Entry<K,V>(hash, key, value, e);
        if (size++ >= threshold)
        resize(2 * table.length);
        }
        此時把新的添加進table[i]位置,而原來的數據(可能是null也可能是一個鏈表)的引用直接存放進新的數據的next中。形成新的鏈表。
        接下來就是調用map的get(key)方法了。這個過程和put方法是逆向的。
    public V get(Object key) {
    if (key == null)
    return getForNullKey();
    int hash = hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
    e != null;
    e = e.next) {
    Object k;
    if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
    return e.value;
    }
    return null;
    }

        首先判斷key == null, 如過為true,那么調用getForNullKey()方法。遍歷table[0]出的鏈表,因為空key是存在table[0]處的。前面說到。
        private V getForNullKey() {
        for (Entry<K,V> e = table[0]; e != null; e = e.next) {
        if (e.key == null)
        return e.value;
        }
        return null;
        }
        如果key == null 為false,那么上面get方法的下半部分,通過hashCode算出hash,通過hash和table.length算出位置i,遍歷table[i]處的鏈表,ken相等,取出數據。
    int hash = hash(key.hashCode());
    for (Entry<K,V> e = table[indexFor(hash, table.length)];
    e != null;
    e = e.next) {
    Object k;
    if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
    return e.value;
    }
    return null;

        這里還有一個Java里面的規定,就是2個對象的equals相等,那么hashCode也必須相等。但是hashCode相等equals不一定相等。這是hashmap存在于Java里面的依據,同時這就是為什么會有沖突的原因了,兩個不一樣的對象計算出來的hashCode相等的原因。如果2個對象equals相等,但是hashcode不想等,那就說明這2個元素都能存進hashmap,但是很明顯hashmap里面的key是唯一的,直接就推翻了hashmap。
        寫得比較粗糙,HashMap里面的很多細節都沒寫,主要是因為一來我們只需要用HashMap就行了,二來是細節源碼里面都有,看一下就知道了。

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

    群體測試活動指導總結

    信息技術世界正從由企業驅動向由客戶驅動轉變,客戶需要更的靈活性以便他們可以通過各種環境和體系去操作其設備。這就向軟件設計師和他們的質量保證團隊提出了挑戰。高質的設計和功能是建立客戶忠誠度的先決條件,。群體測試讓實際用戶在真實條件下測試軟件。這就使公司能夠快速廉價地搜集真實的看法,反饋和缺陷,從而顯著改進質量和設計,并通過客戶和最終用戶提高軟件采用率。使用群體來測試軟件改善了外包或自動化等其他常見選擇的質量,靈活,速度和成本水平。如今,精心設計和高質量的軟件是建立客戶忠誠度的先決條件。為了確保軟件滿足客戶對精準設計,實用性和性能的期望,有必要進行廣泛的測試。軟件要在各種不能提前預測的設備和使用場景上執行。內部測試的測試資源有限,不能滿足如此廣泛的測試覆蓋要求。眾包軟件測試讓真實用戶在真實條件下測試軟件,這樣企業就能快速廉價地搜集真實的看法,反饋和缺陷,從而顯著改善質量。
      1.引言
      過去幾年,眾包模式已從不起眼、被孤立的自定義行為演變成了成功案例,如維基百科和亞馬遜土耳其機器人。在信息技術領域,眾包軟件測試越來越多地被關注及采用,尤其是創業公司和小公司。但是,大企業的采納過程相當緩慢,主要是因為缺乏出版商業文獻。為提高大型企業對群體測試的采納率,我們需要討論一些關鍵問題,如制造或購買的決定,建立一個內部測試社區或與外部機構合作,應用程序適應性,管理和測試員質量,并通過提供一些成功的群體測試活動指導作總結。
      2.今天的IT環境
      近年來,信息技術(IT )已認識到它的戰略重要性,許多企業已對ERP,CRM和其他業務的工具進行了大量潛在投資,這表明了企業IT的關鍵性質。這些公司也有面向消費者的要素,如網站和移動應用程序,這些要素不僅是精心設計的,而且還提供無中斷的功能。預測此類系統的用戶并先驗他們的喜好幾乎是不可能的。眾包軟件測試可以通過確保該軟件無缺陷幫助大幅提高消費者接受軟件模塊的概率。隨著云計算, BYOD等不斷增長的趨勢,IT服務被交付到多個渠道并被IT系統配置不同的各利益相關者使用。真正強大的軟件測試很費時,而且幾乎無法保證功能,位置和平臺的每一個可能的排列組合能如期工作。例如,如果一個Web應用程序無法在某個特定瀏覽器上運行,或一個特定的軟件工具無法使用一個重要功能,那么業務可能會中斷。通過群體測試,企業可以有效地降低內部軟件測試團隊在內部測試階段錯過關鍵要素的可能性。根據Paul Herzlich,一名Ovum(一家獨立的IT業研究機構)的軟件測試分析師的看法,“如果你正在測試一個各種陌生人都要使用的軟件,干嘛不讓一大幫陌生人來測試它呢。”于是,群體測試給或許會成為一個棘手難題的測試提供了一個簡單,簡練,有成本效益的解決方案



      圖2.眾包的各地利益(從谷歌走向看)



      3.探索和企業群體測試
      目前,大部分重點是探索性群體測試服務,測試人員根據通用準則和測試用例分析軟件的問題,bugs,或缺陷。有了“不受約束的”探索性測試,結果不能定量預測,因為要提前限定范圍,地區和可能存在的缺陷數量很困難。測試人員通常可以發現在最明顯地方的問題,但一些高水平測試人員可能會發現軟件層下的缺陷。探索性測試最適合用于測試有大量用戶但不重要的應用程序,以確保不同配置下的一系列問題的再現性或在應用程序上模擬一個典型工作內容。企業群體測試集成在軟件測試過程中更加嚴謹,包含更多結構,同時保留了探索性測試的精神和敏捷性。因此,企業群體測試包括正規和非正規的軟件測試方法的最佳實踐和概念。企業眾包軟件測試的專業程度更高。在這種方法中,測試人員均須經過嚴格審核,并根據全面的選擇標準部署。軟件測試過程包括明確規定的范圍,并由廣泛的特定指導方針指導以滿足項目需求。團隊已明確規定了角色和職責,一個聯系客戶組織,正式報告和報告結構,廣泛文檔和項目跟蹤等的單獨社區點。此外,企業群體測試包括建在現有軟件測試方法上的正式程序,例如Agile,SCRUM等。這樣對齊的結果是,客戶組織的內部開發和外部軟件測試周期間輕松同步了。這就使客戶端可以減少其項目管理的開銷并最大化兩隊的利益。


      圖3


      4.什么樣的應用程序適合用眾包測試?
      眾包測試方法最適合以用戶為中心的應用程序。它常常,通過在公測階段推出廉價或免費產品版本,被用于移動應用和游戲開發項目中。大型企業可以通過模擬一個龐大的用戶群去了解使用模式并根據反饋進行完善同時確保其應用程序在各種設備,操作系統,瀏覽器和語言版本中流暢運行而獲益。換句話說——有高缺陷暴露因素,即關鍵性作為即時客戶發布后暴露的措施的應用程序適合用群體測試。例如,微軟發布Office 2010產品系列的測試版本,被900萬人下載和測試并提供了2百萬條寶貴意見和見解,從而使產品獲得確實的改進。
      5.它是如何運作的呢?
      大多數眾包測試公司為測試周期提供平臺和項目管理框架,包括管理政府和法律結構。群體測試公司還分配一個負責測試過程的合適的項目經理。眾包軟件測試服務的消費者方面,客戶指定他們希望執行的測試類型和測試系列,測試員的技能和個人信息,軟件必須在上面進行測試的設備的類型和配置等。客戶公司也可以咨詢群體測試公司確保測試充分。供應商方面,測試人員完成一個配置文件,表明他們的背景和資歷,他們有權訪問的設備和平臺,以及其他相關細節。測試人員有時需要參加評估或試驗項目作為他們成為社區成員的先決條件。在項目啟動之前,會給測試人員提供詳細的測試計劃,示例場景,工具,腳本和說明。在執行過程中,測試人員記錄下他們的觀察,并根據觀察報告的數量和質量被評分,這與他們的薪酬和激勵結構直接掛鉤。社區結合協作和競爭,成員合作找出解決方案說明問題。論壇促進知識管理,網絡以及bugs或相關問題的討論;評分系統可以識別所做的出色工作,這有助于參與者獲得信譽并完善自己的職業生涯。群體測試應被視作產品發布前的額外補充測試而不是一個獨立的活動及一個組織內部測試團隊的替代品。這對在生產前發現誤差UI和配置缺陷很有效。


      6.現場,外包和測試群體
      現場測試是指為了軟件測試目的部署一個內部團隊的一貫做法。這種方法在可擴展性方面有局限,且對再現現實使用情況無效。外包軟件測試中,外部服務供應商基于每個項目或協議提供軟件測試。外包軟件測試具有明顯的成本優勢——高技能資源只占一小部分成本——通過勞動套利。在群體中測試中,測試人員自愿測試軟件,內在驅動其去發現軟件缺陷,在社區內自己的一席之位,獲得同行的認可,等等,盡管沒有發現缺陷他們就沒有薪酬。這種自發組織的特征,共享社區目標,內在動機是群體測試成功的強大力量。
      7.選擇什么呢?
      現場團隊,因為接近客戶,可以通過關注需要立即關注的技術和商業挑戰創造價值。在一個外包測試項目中,測試團隊(S)可以受外包公司控制也可以不受之控制。受控模式中,測試團隊是公司的一部分,它們把軟件測試作為一項持續性活動(測試團隊可以從中通過對最常見的內部應用程序的更深理解而獲取經驗和效率水平)進行。不受控團隊是公司外部的,它們與一些客戶合作一些項目。從這些約定來看,不受控團隊匯集了多個地方,領域,功能,行業,技術方面的經驗和專業知識。客戶公司可以在需要“創造性思維”和特殊測試工作的項目中利用這種多樣性。群體測試團隊的焦點,重心,內在動力和可擴展性,通過在上線前發現問題提供巨大的價值。群體知識在測試員基地中擴散,但集體測試的知識基地大于任何公司內部基地。考慮到現代系統的復雜性,最佳的測試組織按正確比例應包括現場,外包和眾包測試團隊。按正確比例匯集是經驗和實驗一個關鍵因素。
      8.建立一個社區還是建立合作伙伴關系?
      雖然一些公司,如Netflix和亞馬遜,已經在內部建立了他們自己的群體功能,但這不是大多數公司能夠自己實現的或有戰略性商業意義的活動。群體測試是一項復雜的活動,需要深厚的技術,功能和業務知識。所以,除非要完成的工作是高度戰略性或機密的業務,公司最好立即尋求提供所有必要成分的群體測試公司來部署群體。這些成分包括有經驗的測試人員,設備,可配置架構,參與機制,基本規則,參與方法,法律結構,支持機制等。
      9.安全和管理
      往往,客戶保密信息在測試期間面向群體。群體測試企業已經意識到了安全性和保密性的需求;因此,他們有各種過濾器,管理機制,模糊處理工具,數據管理框架等,以向他們的客戶確保他們的數據和信息極度保密處理。對于對安全性要求高的項目,擁有長期信譽和專業聲譽的白帽測試工程師的預先篩選名單會被提議,且通常會被接受。測試數據管理通過混淆敏感信息或創建“只測試”數據以確保安全。這有助于減少大規模測試中潛在安全漏洞的影響。測試人員加入社區時還必須簽署一份常規保密協議(NDA),禁止他們線上線下在社交網絡、個人博客及其他秘密測試平臺外的地方談論他們的客戶,產品等。客戶也可以自由地從池中選擇自己的測試人員并在看顧客項目之前提供每個被選測試人員必須簽署的自定義NDAs。此外,標準的溝通渠道,準入限制等在測試工作中幫助確保數據并保密,這就使得群體測試項目生命周期各階段可以無縫過渡。
      10.確保測試質量
      為了保證測試員的質量,正式和非正式的測試,可以根據測試員的經驗,可用材料和所掌握概念定期由單個測試員管理。測試人員和項目經理不斷監控以確保質量和完整性。經過不斷的篩選,沒有正式培訓和顯著專業經驗的申請人被淘汰。越來越多地,群體測試公司也贊助有經驗的測試人員去考專業證書,所以他們的地位和責任隨著他們的貢獻而增長。為了避免測試人員之間的潛在利益沖突,實行基于績效的薪酬機制以確保測試人員的報酬與他們的參與度和對軟件質量改進的貢獻水平一致。發現大量不重要缺陷的測試員的報酬低于發現少量極具影響力的缺陷的測試員。這些機制也有利于防止社區內的任何口水之爭,陰謀詭計等,并提高測試者對社區的關注,所有權,忠誠度和隸屬關系,從而創造一個和諧的,彼此尊重的工作環境。
      11.選擇一家群體測試公司
      群體測試過程的各個階段中,選擇合適的測試公司無疑是最重要的。客戶公司在選擇一個群體測試平臺之前要進行充分調查,廣泛的項目評估,測試公司的能力和規模等都是必須的。一般情況下,選擇一個成熟的,經驗豐富的群體測試平臺,可以使業務活動更加容易,因為這樣在運行階段通常就不怎么需要維護及管理,因為測試公司已經根據過去與其他客戶合作的經驗解決了許多相關問題。因此,至少按下列標準評估群體測試平臺以確保平臺至少包含所需的最少功能和安全非常重要:
      一.確定群體測試的經驗,交付能力,技能多樣性,全球拓展情況以適應企業客戶不斷變化的需求很重要。
      二.與企業和中型公司合作的有機增長及經驗表明了可靠性。讓小型的眾包測試平臺提供移動應用程序和網站測試服務相當簡單,但很少有企業成熟到可以測試企業應用程序并提供總包測試服務。
      三.如果客戶公司一心進行長期項目而不想擔心服務提供商退出的話,一段時間內的財政穩定就尤為重要。
      四. 許多群體測試平臺僅有客戶端和測試人員之間牽線搭橋服務,而不提供管理服務。這些平臺不保證軟件測試人員的數量,各個測試人員的測試工作量,測試人員的質量或測試結果,也沒有任何可靠的結果。最好避免這樣的平臺。
      五.要了解它們的服務范圍和所提供的SLA,必須刻苦溫習條款。
      六.標準文檔的采購級層應該用于為每一個重要的群體測試項目評估平臺運營商。該文件應處理各種元素,如:
      1.價格結構
      2.質量,安全,保密性
      3.專業的服務
      4.功能和流程
      5.交付方法
      6.服務基礎設施
      7.補償結構
      8.便利性和可擴展性
      9.平臺和工具的功能和質量
      10.風險管理結構
    總結
      已經討論過群體測試的各種元素,可以很容易地推斷,大企業可以通過既定的和有經驗的群體測試公司合作,以節省大量成本并獲得可擴展性。群體測試工具,流程,框架和方法已經成熟到如此高的程度,那么群體測試就可以很容易地融入組織的常規開發周期。群體測試通過一個更大團隊中的多種軟件測試活動減少人為錯誤的可能性。通過把應用程序提交到現實中,可以追蹤到能重新設計或改進的實際性能數據和執行路徑,從而進一步改進產品質量。除了這些直接的好處,大公司還可以體驗更快的產品上市時間,把資源都放到核心業務上,獲得大量人才,增加靈活性等。開始很容易,而那些敢于冒險嘗試的組織肯定可以獲得一些短期和長期的好處。

      Dieter Speidel是PASS集團的創始人和CEO,一名重要的瑞士軟件和系統測試服務的供應商。 PASS集團是passbrains.com的所有者和passbrains之家,一個在蘇黎世,柏林,波士頓,貝爾格萊德,班加羅爾和孟買都設有辦事處的按需群體測試服務的全球平臺。作為一名在IT外包,軟件開發和測試業活躍了30多年的企業家,Dieter Speidel對全球交付模式,包括近/離岸外包和眾包方面有深入的專業知識。2011年以來,他一直專注于從眾包模式的應用深入到IT相關的服務,并開發passbrains平臺和社區的群體測試和知識服務。
      Mayank Mittal是應用程序測試行業的一名戰略性業務領導。十多年的職業生涯,他已建立了大規模的管理測試中心并在與領先機構,如Oracle、CSC、Cognizant合作時進行了QA組織變革,為全球許多財富100強客戶提供了測試解決方案。Mayank在PASS集團股份公司擔任公司戰略和業務發展主管。
      Mithun Sridharan是Passbrains的一名業務發展經理,Passbrains總部設在德國Eschborn 。他在業務發展,市場營銷,全球交付和咨詢方面有十多年國際經驗。他是工商管理碩士(MBA)和科學碩士(M.Sc)。他是一名項目管理專業人員(PMP)和國際信息系統審計師(CISA) 。他還擔任德國外包協會的通訊主席。

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

    在QTP中申明XPath

     Example 1:
      <body>
      <h4>John Smith<input type=checkbox name="select" /></h4>
      <body>
      <h4>Anne Anderson<input type="checkbox" name="select" checked=true /></h4>
      In QTP:
      'Selecting John Smith
      Browser("XPath").WebElement("xpath:=//h4[1]").Click
      'Selecting Anne Anderson
      Browser("XPath").WebElement("xpath:==/h4[contains(text(), 'Anne')]").Click)
      Example 2:
      XPath:
      1. (//tr[@class='row2']/td[1])[2]
      2. (//td[contains(text(),'Address')])[2]
      In QTP:
      1. Browser("XPath").WebElement("xpath:=(//tr[@class='row2']/td[1])[2]").Click
      2. Browser("XPath").WebElement("xpath:=(//td[contains(text(),'Address')])[2]").Click
      Example 3:
      <table id='table1'>
      <tr class='row1' id=BPT>
      <td>View ID</td>
      <td><input type='button' value='Button 1' class='btn_blue' id='btnfirst'></td>
      </tr>
      In QTP:
      'Selecting Button 1
      Browser("XPath").WebButton("xpath:=//td/input[@id='btnfirst']").Click
      'Select Button 1
      Browser("XPath").WebButton("xpath:=(//table[@id='table1']/*/*)[1]/*[2]/input").Click

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

    軟件測試員——面試,你準備好了么?

     最近有機會做一些面試工作,主要負責面試軟件測試人員招聘的技術面試。
      之前一直是應聘者的角色,經歷了不少次的面試之后,多少也積累一點面試的經驗,現在發生了角色轉變。初次的面試就碰到個工作年限比我長的,也沒有時間仔細了解對方的簡歷,再加上應聘者比較“強勢”。面試情況是比較糟糕的。
      有同學會說,唉!不就失去了一個應聘者嘛。多面幾個就好了!這不單單是失去應聘者,面試者對面試官的印象更重要。面試官的能力與表現對于初次面試者來說往往代表的是公司的,更具體點是測試團隊的能力。
      如果面試官都很“水”,這個水兩方面,一是面試不夠從容,思路不清晰。二是技術能力水,問半天問不到關鍵點上。那么身為面試者,對這家公司的印象會打折很多,就算能開得起面試者的期望薪資,面試者還要考慮在你這兒能不能學到什么,工作是否有挑戰,是否有發展空間。
      所以,面試官的能力與表現對面試是否成功同樣重要,畢竟就面試過程而言是一個雙向選擇的過程嘛。
      下面討論測試人員應該具備的技能。
      在這個討論的過程中,充滿了我個人的偏見與喜好。不喜誤噴!
      上面是我所畫的一個體系圖,這上面的技能相對比較通用,當然特殊情況下對測試人員的技能要求會有特別要求。
      軟件測試基本知識:
      這一塊其實沒什么好討論的,如果你有半年到一年的工作經驗的話,對這一塊一定有比較清晰的認識,當然,在實際的工作中不需要你對每一種測試方法去尋根求源,知道這些方法的含義與應用場景即可。
      編寫各種測試文檔,對于初學者來說稍有難度。但終究還是談不上什么技術含量的事情,如果對業務和流程足夠熟悉,文檔用例自然就會寫了。
    測試輔助技能:
      我發現這兩項技能在筆試和面試過程中必考,出現幾率超高,但在實際的工作中,有些測試根本碰不到linux ,有些測試不需要去操作數據庫。當然,測試嘛,也不能太處于表面了,也需要熟悉熟悉相關測試的表,了解了解系統服務器。
      好在這兩項技能的要求都不高,linux 大多考幾個常用命令,SQL一般考一下增、刪、查、改。
      自動化技術(UI):
      大多同學會在簡歷必備測試技能里加一個QTP自動化測試工具,當我滿懷起到和他聊一聊自動化時,得到的多大回答是這了解和學習過這個工具。這也不能怪測試人員,誰讓滿大街的招聘要求上都寫著“要求熟悉LoadRunner 、QTP等自動化測試工具等。” 其實,他們公司根本就不用。這么多公司都要求,看來還是有必要學一學這個工具的。
      對于我而言,我并不太關心工具用得多熟練?對于web應用來說,更在意的是對前端技術了解多少?因為你要自動化的對象就是前端技術所呈現出來的各種功能。都不了解它,如何定位和操作它呢?
      UI的自動化不單單是QTP一個工具,如果你掌握了一種語言,做自動化的路就寬廣了,你一定知道還有個叫selenium(webdriver)的自動化工具,你不一定知道ruby 有個watir框架也可以做自動,也許你不知道python有個splinter框架也可以做自動化。那么你就更不知道python 有個pywinauto框架可以對windows GUI做自動化。你不知道有自動化工具太多太多了。談到這些就不得不涉及到編程技術了。相比較而言QTP 不需要太多的編程能力。
      對于自動化測試,另一個比較關心的是你對自動化的理解,什么情況下適合做自動化?你的自動化測試用例是怎么寫的?什么樣的用例適合轉成自動化?你是如何來實施的?有什么樣的策略來開展自動化工作?你需要自動化在項目中達到一個什么樣的預期和效果?只是學學工具,拿個例子練習練習。很難對這些問題有真實的理解。
      性能測試:
      LoadRuner似乎比QTP名氣更大,做測試必玩工具。沒摸過LR都不好意思說自己是做測試的。性能測試是必須是要借助工具來實現了。不借助工具如何模擬成百上千的并發?
      最大的難點,其它是對系統架構的理解,其實,更多時候并不需要達到架構師水平,甚至不用達到開發的水平,但起碼,你要弄清用的什么操作系統,什么數據庫,什么開發語言與框架,什么中間件吧!你要知道如何對這些做監控的吧!你要知道叫上開發一塊玩吧!
      對于性能測試,另一個我更關心的測試流程,你做性能測試的目的是什么?新系統驗證?還是舊系統擴容?需要達到一個什么樣的預期?在獨立的環境可以開展么?壓力在哪兒,腳本為什么要這樣錄制?你的測試結果真的有知道意義么?或對系統性能做出了合理的評估,或為系統有調優做出指導,或為系統擴容做出了依據。如果前因后果弄不清何必去做呢?
      編程能力:
      編程不局限于語言,大多同學也會在簡歷的必備技能最下方面寫上一條,熟悉C語言或其它某種語言。大多止步于大學C語言水平。工作中沒有機會用到。所以,就沒機會去進一步提升這方面的能力。這似乎也挺合乎情理的,再說你們招的是測試又不是開發。
      不過,我個人偏執的很看重這一點,至于上面的自動化、性能會不會都無所謂,如果在編程能力上略懂一二,我會大力推薦。懂編程和不懂編程的人看系統的深度不一樣,一點不懂的只能看出來這是按鈕,那是輸入框。 懂編程的就知道你的登錄是個<from> ,輸入框是個<input> ,你的登錄提交是用的post 還是get呢?邏輯層就是獲取到輸入的用戶名密碼是查數據庫做比較嘛。在測試過程中不管功能實現也好,bug也好,都會看得更透徹,從而更容易挖掘出相關的bug。
      一般懂編程的我都會讓其寫一個小程序,例如求素數,遞歸調用,用星號(*)打印一個梯形,如果測試工作寫一些腳本之類的來輔助測試更是大大的亮點。不要覺得讓你寫程序就是“刁難”。平時注意積累這又何難呢?
      對新的工作有什么期待?
      “我希望能接觸一些性能測試、自動化測試等,因為之前的工作一直在做功能。”
      大多數測試人員認為提升自已的過程是這樣的:
      現在有一個性能需求,然后領導找到你說,小張啊,你來研究研究性能測試吧!我們現在的需要迫切需要對系統做一次性能測試,然后,你回去開始研究性能測試,花一個月終于搞懂了,開始對系統做性能測試。最終完成了任務。
      但實際的情況是這樣的:
      現在有一個性能需求,然后領導找到你說,小張啊,你會做性能測試么?答,這個以前沒做過,得學習一下。領導說:噢,那這樣吧!小王你回去了解一下吧。因為小王雖然也沒搞過,但他平時做測試的資歷更久,對于新技術更愛鉆研。在領導看來,小王能在更短的時間搞定這個問題。如果這個需求迫切或要求更專業,領導會直接招一個專業做性能的。
      所以,結論很明了,機會是給有準備的人的。假如,你在某一技能上面持續積累,總會有發光的時候。
      面試官更多的時候是在找亮點,我只有一個崗位,在面試的十個人當中,有十個人都能把測試流程什么的說得順溜(雖然我也只招一個懂測試會流程就行了)。有八個人說自己懂QTP、LR等工具,只有兩個人真正的有自動化或性能測試經驗,只有一個人編程方面還不錯。你說面試官會選誰呢?
      亮點也是談資(談錢的資本),你和前一個面試者差不多,前一個面試者要5K,你要8K,那我更傾向于前者,如果你有別人沒有的亮點,那我更傾向于有亮點者,我更愿意招個牛B的,工資又不是我給你開,最終是否談攏是你和人事或上級的事兒。
      面試是個綜合的過程,假如你思路清晰,思維敏捷。假如你和我一樣有寫博客的習慣。或者談談你最近看的兩本技術書。讓我看到你是個工作很有熱情的人,你是個熱愛技術的人。這都是和別人不一樣的亮點。閃閃發光。到哪兒都發光。

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

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

    導航

    統計

    常用鏈接

    留言簿(55)

    隨筆分類

    隨筆檔案

    文章分類

    文章檔案

    搜索

    最新評論

    閱讀排行榜

    評論排行榜

    主站蜘蛛池模板: 91亚洲国产成人久久精品网站| a毛片成人免费全部播放| 日本亚洲成高清一区二区三区| 夭天干天天做天天免费看| 免费视频成人手机在线观看网址| 免费在线观看亚洲| 亚洲最大福利视频| 亚洲中字慕日产2020| 亚洲国产高清视频| 久久亚洲综合色一区二区三区| 免费v片在线观看品善网| 午夜a级成人免费毛片| 青青视频观看免费99| 91香蕉在线观看免费高清| 国产又黄又爽又大的免费视频| 日本高清免费中文在线看| 国产精品观看在线亚洲人成网| 亚洲永久在线观看| 亚洲AV无码久久久久网站蜜桃| 日韩精品亚洲人成在线观看| 亚洲日韩国产精品第一页一区| 亚洲美女在线国产| 亚洲精品网站在线观看不卡无广告| 国产福利免费观看| 又粗又大又长又爽免费视频| 成在线人永久免费视频播放| 日韩免费观看视频| 国产免费午夜a无码v视频| 国产无遮挡色视频免费视频| 成年女人永久免费观看片| 四虎永久免费影院| 亚洲?V无码成人精品区日韩| 亚洲AV无码乱码在线观看| 亚洲国产精品无码久久九九 | 久久亚洲国产视频| 亚洲av丰满熟妇在线播放| 亚洲国产二区三区久久| 亚洲日本在线播放| 亚洲日韩精品国产3区| 美国毛片亚洲社区在线观看| 污视频网站免费在线观看|