qileilove

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

          使用VC連接Access數據庫的兩種方法

           以前的時候用VC寫了兩種連接Access數據庫的方法,為了方便以后查找把這兩種方法做一下簡單的介紹。Windows平臺的數據接口標準有ODBC、OLE DB、ADO和Borland的BDE接口,ODBC(Open DataBase Connectivity)只能用于訪問關系型數據庫,為了訪問非關系型數據微軟設計了OLE DB接口并在此基礎上推出了ADO(ActiveX Data Objects)。本文介紹的方法是ODBC和ADO。
            一、使用ODBC接口,在這里我們使用MFC的CDatabase類,該類是對SQLConnect等ODBC的API的封裝。需要包含afxdb.h
          BOOL ODBCConnect(CString strDBFile)
          {
          CString strConnect;
          strConnect.Format(_T("ODBC;DRIVER={MICROSOFT ACCESS DRIVER (*.mdb)};UID=sa;PWD=;DBQ=%s"), strDBFile);
          CDatabase db;
          if(db.Open(NULL, FALSE, FALSE, strConnect))
          {
          //連接數據庫成功
          CRecordset rs(&db);
          CString strSql;
          strSql = _T("select * from info");                                //SQL語句
          rs.Open(AFX_DB_USE_DEFAULT_TYPE, strSql);                        //執行Sql語句(可添加 刪除 查詢等)
          if(rs.IsOpen())
          {
          CDBVariant variant;
          rs.MoveFirst();
          while(!rs.IsEOF())
          {
          //讀取記錄
          rs.GetFieldValue(_T("姓名"), variant);
          rs.MoveNext();
          }
          }
          db.Close();
          return TRUE;
          }
          return FALSE;
          }
           二、使用ADO連接數據庫,因為要使用COM,需要初始化(CoInitialize).然后就可以生成接口的對象操作,代碼如下:
          #import "C:Program Files/Common Files/System/ado/msado15.dll" rename("EOF", "adoEOF")    //生成C++類,改變EOF函數的名稱
          using namespace ADODB;
          BOOL ADOConnect(CString strDBFile)
          {
          _ConnectionPtr pConnection;
          if(pConnection.CreateInstance(__uuidof(Connection)) != S_OK)
          {
          return FALSE;
          }
          CString strConnect;
          strConnect.Format(_T("Provider=Microsoft.Jet.OLEDB.4.0;Data Source=%s"), strDBFile);
          if(pConnection->Open(_bstr_t(strConnect), "", "", adModeUnknown) == S_OK)
          {
          //連接數據庫成功
          _RecordsetPtr pRecordset;
          if(pRecordset.CreateInstance(__uuidof(Recordset)) != S_OK)
          {
          pConnection->Close();
          return FALSE;
          }
          CString strSql;
          strSql = _T("select * from info");
          HRESULT hr = pRecordset->Open(_bstr_t(strSql), _variant_t((IDispatch*)pConnection, TRUE), adOpenUnspecified, adLockUnspecified, adCmdUnknown);
          if(hr != S_OK)
          {
          pConnection->Close();
          return FALSE;
          }
          _variant_t vt;
          pRecordset->MoveFirst();
          while(!pRecordset->adoEOF)
          {
          vt = pRecordset->Fields->GetItem("姓名")->Value;
          pRecordset->MoveNext();
          }
          pConnection->Close();
          return TRUE;
          }
          return FALSE;
          }

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

          實例說明Java中的null

           讓我們先來看下面的語句:
            String x = null;
            1. 這個語句到底做了些什么?
            讓我們回顧一下什么是變量,什么是變量值。一個常見的比喻是 變量相當于一個盒子。如同可以使用盒子來儲存物品一樣,您可以使用一個變量來存儲一個值。當聲明一個變量時,我們需要設置其類型。
            在Java中變量分為兩大類型: 原始值(primitive)與引用值(reference).
            聲明為原始類型的變量,存儲的是實際的值;聲明為引用類型的變量,存儲的是實際對象的地址(指針,引用).
            在上面的語句中, 初始化語句定義了一個變量 "x". x中存放的是String引用,此處為 null.
            下圖對此概念提供了更形象的說明:
            
            如果 x = "abc",則引用示意圖如下:
            
            2. 在內存中null具體是什么?
            在Java中 null 值是什么,在內存中null是什么?
            首先需要明確,null不是一個合法的object實例,所以并沒有為其分配內存.
            null 僅僅用于表明該引用目前沒有指向任何對象。
            我們看看 JVM規范 的描述:
            Java虛擬機規范并不強制要求使用一個具體的值編碼null。
            我認為和其它類C語言一樣,null是對引用變量的值全部置0。
            譯者注: Java對象的屬性域默認初始化其實很簡單,把分配的內存所有位全部置0,所以 數字是0, boolean是false, 浮點是 0.0f, 引用是 null, 因為引用是內存地址,所以可以推測出 null 實際上就是一堆0. 用鼠標手想一想也就明白, 地址 0 肯定是不可以存放任何對象的。

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

          如何確定非功能需求?

          非功能需求一般和系統的狀態有關而與系統需要提供的功能無關。通常是系統的“ ilities”功能,比如可擴展性(scalability)、互操作性(interoperability)、可維護性(maintainability)、移植性(portability)、性能和安全性都包括在此類。敏捷團隊經常糾結于定義和估算項目的非功能需求。
            Mike Cohn建議幾乎所有的非功能需求都能以用戶故事表述。他給出了幾個例子展示非功能需求能夠適用標準的用戶故事模板
            幸運的是約束/非功能需求能很容易的按用戶故事處理。這里給出幾個例子:
            作為客戶,我要在從Windows 95之后的所有版本的Windows上運行產品。
            作為CTO,我要(新)系統使用我們已有的訂單數據庫而不是創建新數據庫,這樣我們就不用再多維護一個數據庫了。
            作為用戶,我要網站在99.999%的時間是可訪問的,這樣我就不會感到沮喪并找其它的網站來用。
            然而,Mike也警告說用戶故事模板只是用來作為一個思考工具。不應該用一個固定的模板來記錄所有的非功能需求。
            Jason建議不要試圖在用戶故事級別記錄非功能需求,團隊應該把它們作為(項目)大圖景的一部分。按照Jason所說,在他的團隊,他們嘗試過在每個單獨的用戶故事級別記錄非功能需求,但是沒起到作用。他提到:
            我喜歡把這些非功能需求(NFR)用戶故事寫在墻上并在工作區都能看到,這樣可以提醒團隊在給出估算時考慮這些約束的因素。
            Mike還提出一種明確的方法來估算非功能需求。按他所說,非功能需求與兩個成本相關聯
            初始遵循(非功能需求)成本——團隊滿足非功能需求所用的工作量。比如,在sprint 5花在性能測試上的工作量。
            持續遵循(非功能需求)成本——在以后的sprint中滿足非功能需求的工作量。
            一旦團隊接受非功能需求作為項目的一部分(就像我們團隊在sprint 5中做的),他們需要把持續達到非功能需求作為項目的提示。我認為這種成本就像上稅。進行性能測試(或者說遵從任何非功能需求)產生了一些額外的開支(稅)。這種開支,或者說稅,是必須定期付出的。
            為了估算,Mike認為這兩種成本需要單獨考慮。初始遵循成本應該和任何其它的用戶故事或產品backlog中的任務一樣被估算。持續遵循成本,團隊和product owner需要決定多久要進行一次遵循驗證工作。
            例如,假設團隊和product owner同意每四個兩周的sprint中進行一次性能測試。團隊估算每次第四個sprint有六個點的工作要做。那就是大約每個sprint1.5點。如果團隊的速度(velocity)是30個點,1.5點可以認為是大約5%的稅。
            Nick Xldis對遵循成本進行了一次非常有意思的觀察。據Nick所說,
            如果這種稅持續增長,那你的架構或流程上就有問題了,需要格外關注。這是對于技術債的很好的晴雨表。
            Scott Ambler通過提升一個獨立測試團隊的能力分享了管理非功能需求的想法。
            Kassab、Olga、Maya和Alain介紹了NFR大小測量方法(NFSM)來減少估算非功能需求中的不確定性。
            因此,處理非功能需求可能不是痛苦的掙扎。關鍵是盡早處理它們并關注持續成本。
            注意:關于非功能需求這一術語的使用有很多想法和爭論。Mike Cohn稱其為約束而Tom Glib強烈建議稱之為質量需求。

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

          使用LoadRunner進行服務器性能測試

           由于項目進入尾聲,需要進行性能測試,沒有專業的性能測試工程師,只好自己動手,研究一下loadrunner.
            發現loadrunner對web測試介紹比較多,牽涉到winsocket測試的資料極少,不過到處找一找,研究一下,也是可行的.
            先說一下我們的協議,采用tcp協議,與客戶端采用自定義二進制流的方式進行通信.遵從普通的自定義協議的方式,即協議結構采用包頭+包體的形式,包頭為固定大小的長度,并在包頭中加入包體總長度的字段.
            好了,下面可以用loadrunner進行協議測試了.首先想法在PC上實現一個簡單的協議生成軟件,我采用python進行編制,將協議跑一遍,然后用loadrunner進行錄制.由于是針對單個的協議錄制,因而在loadrunner中生成的腳本一目了然.考慮到同一條協議根據不同的條件,返回的數據是不一樣的,因此腳本稍有點復雜.
            錄制的腳本默認采用函數lrs_receive()來接收腳本,根據loadrunner的匹配規則,默認用data.ws中recv buf 中指定的長度來進行匹配,這樣,由于同一個協議返回的數據總是不斷變化的,就必然導致測試不通過的情況.在網上查到,可以通過某個設置使得每次達到錄制時的數據量即可,但這樣做有個明顯的缺陷,每次讀到到指定的數據后就不讀取了,針對短連接,或是只測試一次的還可以,要是長連接,需要不停發送和接收的,必然出現測試不準確的問題.
            以下為解決方法,將lrs_receive改為lrs_receive_ex,并將一次讀取改為兩次讀取,第一次讀取固定大小的包頭,讀完包頭后,解析出包體的大小,然后再讀取包體.
            此方法適用所有自定義winsocket協議,附上相關腳本.
          /********************************************************************* * Created by Mercury Interactive Windows Sockets Recorder * * Created on: Fri Jul 13 16:08:19 *********************************************************************/
          #include "lrs.h"
          vuser_init()
          {
          lrs_startup(257);
          lr_start_transaction("create_socket");
          lrs_create_socket("socket0", "TCP", "RemoteHost=127.0.0.1:110",  LrsLastArg);
          lr_end_transaction("create_socket", LR_AUTO);
          return0;
          }
          /********************************************************************* * Created by Mercury Interactive Windows Sockets Recorder * * Created on: Fri Jul 13 16:08:19 *********************************************************************/
          #include "lrs.h"long getNextRecvLen(char* socketID)
          {
          int NumberOfBytes = 0;
          int NextRecvLen = 0;
          char *Buffer;
          lrs_get_last_received_buffer(socketID, &Buffer, &NumberOfBytes);
          memcpy((char*)&NextRecvLen, Buffer+20, 4);
          lr_log_message("last_received:%d, NextRecvLen:%d", NumberOfBytes, NextRecvLen);
          return NextRecvLen;
          }
          int receive_ex(char* socketID, char* buf)
          {
          long NextRecvLen = getNextRecvLen(socketID);//getNextRecvLen("socket0");char flag[50];
          memset(flag, 0, sizeof(flag));
          sprintf(flag, "NumberOfBytesToRecv=%d", NextRecvLen);
          lr_log_message(flag);
          lrs_receive_ex(socketID, buf, flag, LrsLastArg);
          }
          void doOneThing(int index)
          {
          char sendbuf[50];
          char recvbuf1[50];
          char recvbuf2[50];
          char transbuf[50];
          memset(transbuf, 0, sizeof(transbuf));
          sprintf(transbuf, "one_send_recv_%d", index);
          lr_start_transaction(transbuf);
          memset(sendbuf, 0, sizeof(sendbuf));
          memset(recvbuf1, 0, sizeof(recvbuf1));
          memset(recvbuf2, 0, sizeof(recvbuf2));
          sprintf(sendbuf, "buf%d", 2*index);
          sprintf(recvbuf1, "buf%d", 2*index+1);
          sprintf(recvbuf2, "dbuf%d", index);
          lrs_send("socket0", sendbuf, LrsLastArg);
          lrs_receive_ex("socket0", recvbuf1, "NumberOfBytesToRecv=32", LrsLastArg);
          receive_ex("socket0", recvbuf2);
          lr_end_transaction(transbuf, LR_AUTO);
          }
          Action()
          {
          lr_rendezvous("read_all_req_0");
          doOneThing(0);
          }
          /********************************************************************* * Created by Mercury Interactive Windows Sockets Recorder * * Created on: Fri Jul 13 16:08:19 *********************************************************************/
          #include "lrs.h"
          vuser_end()
          {
          lrs_close_socket("socket0");
          lrs_cleanup();
          return0;
          }
            由于是分兩次讀取數據,必然讀取的內容與錄制的會稍有不同,幸好我們判斷成功與否不是用返回的數據進行比較,而只是核對一下數據的大小,因此完全可以手動修改數據腳本,以下為在錄制的基礎上手工修改的腳本(注意,只是更改了接收端)
          send  buf0 28
          "Test"
          "\x00\x1b\x00\x00\x00"
          "\x00\x00\x00\x00"
          "\x12\x01\x00\x00\x00\x01\x00\x00\x00"
          "\x02\x00\x01\x00\x01\x00"
          recv  buf1 -1
          recv rbuf0 -1
           

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

          Selenium—實現網頁元素拖拽

          Drag and Drop, 使用鼠標實現元素拖拽的操作貌似很復雜, 在Selenium中, 借助OpenQA.Selenium.Interactions.Actions類庫中提供的方法, 實現起來還是比較簡單的。道理如下:
            1. 找到要拖拽的頁面元素-源(source)。
            2. 找到要釋放的頁面元素-目標(target), 頁面顯示的這個元素可能是個坑, 但是在頁面代碼中他就是一個元素。
            3. 借助(new Actions(IWebDriver)).DragAnddrop( source, target).Perform(), 完成元素拖放操作。
            示例代碼:
          // drag and drop
          using OpenQA.Selenium.Interactions;
          SIE.InternetExplorerDriver driver = new SIE.InternetExplorerDriver();
          if (source != null && target != null)
          {
          // drag and drop
          new Actions(driver).DragAndDrop(source, target).Perform();
          }

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

          Redis和Ssdb讀取性能對比

          最近關注了一下ssdb,它的特點是基于文件存儲系統所以它支撐量大的數據而不因為內存的限制受取約束.從官網的測試報告來看其性能也非常出色和redis相當,因此可以使用它來代替redis來進行k-v數據業務的處理.想法總是美好的,不過現實中就可能帶點骨感.
            幸好ssdb是兼容redis的部份協議,所以直接用redis client庫就可以進行一個壓力測試.以于針對Redis和ssdb的幾個讀操進行一個簡單的性能測試對比,這個測試不是直接在本機調用Redis和ssdb. 而是通過一個程序在別的服務器上調用.測試指令(get,hget,lregion)以下是測試結果截圖
          class Test
          {
          long mCount = 0;
          long mIndex = 0;
          private bool mRuning = true;
          public long Count
          {
          get
          {
          return mCount;
          }
          }
          public void Execute()
          {
          Console.WriteLine("* -----------------------------------------------");
          Console.WriteLine("* redis get");
          ConsoleWait.Start();
          string result = OnTest(Config.RedisClient,GetHandler);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* ssdb get");
          ConsoleWait.Start();
          result = OnTest(Config.SSDBClient, GetHandler);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* -----------------------------------------------");
          //
          Console.WriteLine("* redis lregion[1-2]");
          ConsoleWait.Start();
          result = OnTest(Config.RedisClient, LRegionHandler1TO2);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* ssdb lregion[1-2]");
          ConsoleWait.Start();
          result = OnTest(Config.SSDBClient, LRegionHandler1TO2);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* -----------------------------------------------");
          //
          Console.WriteLine("* redis lregion[50-60]");
          ConsoleWait.Start();
          result = OnTest(Config.RedisClient, LRegionHandler1TO2);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* ssdb lregion[50-60]");
          ConsoleWait.Start();
          result = OnTest(Config.SSDBClient, LRegionHandler1TO2);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* -----------------------------------------------");
          //
          Console.WriteLine("* redis lregion[100-110]");
          ConsoleWait.Start();
          result = OnTest(Config.RedisClient, LRegionHandler1TO2);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* ssdb lregion[100-110]");
          ConsoleWait.Start();
          result = OnTest(Config.SSDBClient, LRegionHandler1TO2);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* -----------------------------------------------");
          //
          Console.WriteLine("* redis hget");
          ConsoleWait.Start();
          result = OnTest(Config.RedisClient, HGetHandler);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* ssdb hget");
          ConsoleWait.Start();
          result = OnTest(Config.SSDBClient, HGetHandler);
          ConsoleWait.End();
          Console.WriteLine(result);
          Console.WriteLine("* -----------------------------------------------");
          }
          private void HGetHandler(RedisClient e)
          {
          while (mRuning)
          {
          long index = System.Threading.Interlocked.Increment(ref mIndex);
          ProtobufKey key = "user_" + Data.Import.Users[(int)(index % Data.Import.Users.Count)].Name;
          key.Get<Model.Order, Model.Employee, Model.Customer>(e);
          System.Threading.Interlocked.Increment(ref mCount);
          }
          }
          private void LRegionHandler1TO2(RedisClient e)
          {
          while (mRuning)
          {
          ProtobufList<Model.Order> list = "Orders";
          list.Range(1, 2, e);
          System.Threading.Interlocked.Increment(ref mCount);
          }
          }
          private void LRegionHandler50TO60(RedisClient e)
          {
          while (mRuning)
          {
          ProtobufList<Model.Order> list = "Orders";
          list.Range(50, 60, e);
          System.Threading.Interlocked.Increment(ref mCount);
          }
          }
          private void LRegionHandler100TO110(RedisClient e)
          {
          while (mRuning)
          {
          ProtobufList<Model.Order> list = "Orders";
          list.Range(100, 110, e);
          System.Threading.Interlocked.Increment(ref mCount);
          }
          }
          private  void GetHandler(RedisClient e)
          {
          while (mRuning)
          {
          long index = System.Threading.Interlocked.Increment(ref mIndex);
          ProtobufKey key = "user_" + Data.Import.Users[(int)(index % Data.Import.Users.Count)].Name;
          key.Get<Model.User>(e);
          System.Threading.Interlocked.Increment(ref mCount);
          }
          }
          private string OnTest(RedisClient client,Action<RedisClient> handler)
          {
          mCount = 0;
          mRuning = true;
          for (int i = 0; i < 20; i++)
          {
          System.Threading.ThreadPool.QueueUserWorkItem((o) =>
          {
          GetHandler((RedisClient)o);
          }, client);
          }
          int s = 20;
          while (s > 0)
          {
          System.Threading.Thread.Sleep(1000);
          s--;
          }
          mRuning = false;
          System.Threading.Thread.Sleep(1000);
          return string.Format("* [seconds:{1}/total:{0}]", mCount, mCount / 20);
          }
          }
            從測試結果看來差距還是非常明顯,并不象官網那樣說得這么理想.雖然SSDB效率上不如REDIS,但其基于磁盤存儲有著其最大的優勢,畢竟很多業務數據遠超過服務器內存的容量.
            SSDB的測試結果不理想也許是硬件環境受限,如果有個SSD硬盤的測試環境估計也得到一個更好的結果,但在測試過程中發現一個問題就是SSDB占用的CPU資源也是非常大的,在以上測試過程SSDB的并發效率比不上REDIS,同時CPU損耗上基本要比REDIS高出一倍的樣子.
            以上測試結果緊緊是是一些情況下的性能測試對比,不能完全表述出兩者在應用的差距的結果,如果需要用到這些產品的同學不防在實施前進行一些測試為實施選擇提供一個更可靠的結果.
           

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

          很久以前寫的一個功能測試用例

          你要測試windows附件中的計算器,請列出兩個整數相加的測試用例(假設計算器能輸入的數據最大長度為8位)。
            - 整數(雙字節[16bit]):
            有效等價類:≥-32768(-2[-15]-1)且≤32767(2[15]-1)、
            無效等價類:<-32768、>32767
            邊界值:     -32769、-32768、0、32767、32768
            錯誤推測:
            - 無符號整數(雙字節[16bit]):
            有效等價類:≥0且≤65535(2[16]-1)、
            無效等價類:<0、>65535
            邊界值:     -1、0、65535、65536
            錯誤推測:
            僅對第一類給出例子:
            有效的測試用例:(符合整數條件及其整數相加不超過整數范圍的用例)應考慮上述情況
            如:
            100+200=300
            -100+400=300
            0+32767=32767
            -32768+1=-32767
            ......
            無效的測試用例:(不符合整數條件及其整數相加超過整數范圍的用例以及無效的等價類)
            如:
            -1000000+100
            -32769+0
            32767+1
            -32768-1
              ......

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

          RAC數據庫恢復到單實例數據庫

          RAC數據庫恢復到單實例數據庫的基本步驟如下:
            a.準備單實例服務器,pfile文件,啟動到nomount
            b.備份rac數據庫
            c.將備份文件拷貝到單實例服務器
            d.在單實例服務器上還原、恢復
            e.resetlogs打開數據庫
            f.rename redo文件名
            g.disable thread 2并刪除其redo組
            h.增加temp臨時表空間數據文件
            i.刪除不必要的undo表空間
            業務需要(比如,測試備份)將RAC數據庫通過備份恢復到單實例服務器;下面是實際操作步驟;測試環境:RHEL4u7、oracle 10gR2、ASM、2節點,單實例服務器:RHEL4u7、oracle 10gR2、文件系統;在測試環境下,RAC 數據庫文件都在asm時,在rename file操作時會遇到了BUG問題,最后的恢復時則需要重建控制文件;上面介紹的步驟是指沒有BUG的情況的操作;
            另外,備份、拷貝的環節就請參考其他文檔,就不介紹了,下面從第4步在單實例服務器上還原、恢復與打開開始介紹;
          RMAN> startup nomount
          RMAN> restore controlfile to '/app/oracle/oradata/ctl01.dbf' from '/app/oracle/backup/ctl_23_1_855331400';
          RMAN> run{startup mount;
          set until sequence 870 thread 1;
          set newname for datafile 1  to '/app/oracle/oradata/system.257.779207027';
          set newname for datafile 3  to '/app/oracle/oradata/sysaux.262.779207043';
          set newname for datafile 4  to '/app/oracle/oradata/users.260.779207053';
          set newname for datafile 2  to '/app/oracle/oradata/undotbs1.264.779207043';
          set newname for datafile 15  to '/app/oracle/oradata/pptest_tbs.282.793979093';
          set newname for datafile 5  to'/app/oracle/oradata/undotbs2.268.779207507';
          set newname for datafile 8  to'/app/oracle/oradata/tbs_p3w.271.780396123';
          set newname for datafile 9  to'/app/oracle/oradata/tbs_p4w.274.780396125';
          set newname for datafile 6  to'/app/oracle/oradata/tbs_p1w.270.780396121';
          set newname for datafile 7  to'/app/oracle/oradata/tbs_p2w.273.780396123';
          set newname for datafile 14 to'/app/oracle/oradata/pptest_tbs.279.781454807';
          restore database;
          switch datafile all;
          recover database;
          }
          sys@racdb3> alter database rename file '+DG/racdb/onlinelog/group_1.263.779207025' to '/app/oracle/oradata/redo1.log';
            rename 完所有redo文件后,即可resetlogs打開數據庫;但是,實際操作中遇到bug7207932:Rman Restore From RAC ASM To Single Instance Non ASM Fails With ORA-00600 [kgeade_is_0] (文檔 ID 1146703.1)
            Bug 7207932  ORA-600 [KGEADE_IS_0] WHEN RENAMING A FILE FROM ASM TO FS
            要想繞開的方法則是重建控制文件后,再打開數據庫
            sys@racdb3> alter database backup controlfile to trace as '/tmp/ctl.trc' reuse resetlogs;
           打開trace文件,修改里面的logfile部分信息;然后重啟數據庫到nomount狀態;
          sys@racdb3> shutdown immediate
          SQL> STARTUP NOMOUNT
          CREATE CONTROLFILE REUSE DATABASE "RACDB" RESETLOGS  ARCHIVELOG
          MAXLOGFILES 50
          MAXLOGMEMBERS 2
          MAXDATAFILES 2000
          MAXINSTANCES 8
          MAXLOGHISTORY 292
          LOGFILE
          GROUP 1 '/app/oracle/oradata/group_1.263.779207025'  SIZE 10M,
          GROUP 2 '/app/oracle/oradata/group_2.259.779207027'  SIZE 10M,
          GROUP 3 '/app/oracle/oradata/group_3.258.779207027'  SIZE 10M
          DATAFILE
          '/app/oracle/oradata/system.257.779207027',
          '/app/oracle/oradata/undotbs1.264.779207043',
          '/app/oracle/oradata/sysaux.262.779207043',
          '/app/oracle/oradata/users.260.779207053',
          '/app/oracle/oradata/undotbs2.268.779207507',
          '/app/oracle/oradata/tbs_p1w.270.780396121',
          '/app/oracle/oradata/tbs_p2w.273.780396123',
          '/app/oracle/oradata/tbs_p3w.271.780396123',
          '/app/oracle/oradata/tbs_p4w.274.780396125',
          '/app/oracle/oradata/pptest_tbs.279.781454807',
          '/app/oracle/oradata/pptest_tbs.282.793979093'
          CHARACTER SET ZHS16GBK
          ;
            創建完成后,用backup controlfile進行恢復;
          sys@racdb3> RECOVER DATABASE USING BACKUP CONTROLFILE until cancel;
          sys@racdb3>ALTER DATABASE ADD LOGFILE THREAD 2
          GROUP 4 '/app/oracle/oradata/group_4.265.779207453' SIZE 10M REUSE,
          GROUP 5 '/app/oracle/oradata/group_5.266.779207459' SIZE 10M REUSE,
          GROUP 6 '/app/oracle/oradata/group_6.267.779207467' SIZE 10M REUSE;
          sys@racdb3> alter database open resetlogs;
          成功resetlogs打開后,還需要做一些去thread 2的操作;
          sys@racdb3> alter database disable thread 2;
          sys@racdb3> alter database drop logfile group 4;
          alter database drop logfile group 4
          *
          ERROR at line 1:
          ORA-00350: log 4 of instance UNNAMED_INSTANCE_2 (thread 2) needs to be archived
          ORA-00312: online log 4 thread 2: '/app/oracle/oradata/RACDB/onlinelog/o1_mf_4_9ym2kvgf_.log'
          sys@racdb3> alter database clear unarchived logfile group 4;
          sys@racdb3> alter tablespace temp add tempfile '/app/oracle/oradata/temp01.dbf' size 10M reuse;
          Tablespace altered.
          sys@racdb3> drop tablespace undotbs2 including contents and datafiles;

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

          關于Java加殼和代碼混淆

           在C中,進行代碼加密,首要經過加殼的方法。所謂加殼,即是先將程序代碼加密,然后用特定的程序加載器,將代碼解密后加載進內存,這樣能夠在避免代碼的反編譯,當然,有加殼東西,也有解殼東西,盡管不能100%避免crack,但仍然給代碼增加一層有力的維護。
            然而在Java中,維護代碼是件很困難的工作,由于class文件十分標準,很容易反編譯,且反編譯后的代碼明晰可讀。常見的維護辦法是運用代碼混淆器,打亂class和function以及變量的姓名,能夠攪擾反編譯后的代碼的可讀性。盡管簡略提高了代碼的安全性,但還僅僅適當于未加殼的C程序。
            java能夠加殼嗎?曾經我以為這是不能夠的,由于動態加載代碼這樣的內存等級的操作,java無法做到,除非運用JNI(JavaNativeInterface),調用自個編寫的C代碼,在C代碼中完成動態加載java代碼。可是,C如何加載java代碼呢?這需要對JVM適當的知道。所以其時的我以為這是不能夠的。
            然而,最近接觸的一些常識告訴我——java也能夠加殼!!
            1.URLClassLoader。用URLClassLoader能夠在java程序的運轉時間,再將文件夾或許jar加入到classpath中,這個特性事實上即是動態加載。既然能夠動態加載class的文件夾或許jar,為何不能夠加載加密后的classes呢,將classes用自個的方法加密,在URLClassLoader調用時,運用自個的方法解密。不即是達到了加殼的目的了嗎?不過解密的代碼放在何處是個疑問,即是說解殼器的代碼暴露在外,仍是很風險的。
            2.javassist。這實在是一個十分奇特的新技能,我是在學習Tapestry5時首次遇到這個包的,他能夠動態創立java字節碼,乃至能夠修正你現已寫好的函數,比如你的getter和setter,僅僅簡略的讀取和賦值,你能夠在Runtime用他修正你的getter和setter,讓你的getter和setter每次調用時都能夠觸發某些代碼。憑借這項奇特的技能,必定能夠完成更強壯的動態加載,加殼也就有了能夠。

          posted @ 2014-08-26 09:42 順其自然EVO 閱讀(1913) | 評論 (0)編輯 收藏

          51Testing專訪史亮:測試人員在國外

            版權聲明:51Testing軟件測試網原創出品,轉載時請務必以超鏈接形式標明文章原始出處、作者信息和本聲明,否則將追究法律責任。
            史亮,東南大學計算機軟件與理論專業博士,研究領域為軟件分析與測試。2006年加入微軟(中國)有限公司,任職軟件開發測試工程師,負責微軟在線業務與商業智能產品的測試工作。2011年調至微軟總部,從事Microsoft Office 2013的測試工作。2012年與淘寶測試工程師高翔合著了《探索式軟件測試實踐之路》一書。2014年,獨自出版了《軟件測試實戰:微軟技術專家經驗總結》。目前,史亮正從事下一代Microsoft Office產品的研發工作。
            51Testing:史亮老師,您好,歡迎做客51Testing。聽說您目前在國外工作,您是出于什么原因選擇去國外工作的?
            史亮:在2011年,我打算更換工作環境,以接觸更多的新技術和重要產品。于是,我主動申請工作調動,然后通過內部面試流程,獲得了微軟總部的工作機會,所在部門是Microsoft Office。
            51Testing:您去國外大概多長時間了?主要的工作內容是什么?
            史亮:從2011年到現在,我已經在微軟總部工作了整整三年。最初我加入Microsoft Office部門,主要負責的是Microsoft Office 2013的研發,工作內容是測試Windows版本的Office產品。目前,我正參與研發下一代的Microsoft Office,主要工作是測試產品和開發測試輔助工具。
            51Testing:很多朋友剛出國時會有不適應,您是否也如此?在國外工作了三年,您感覺國外公司和國內公司存在哪些差異?(例如管理、工作環境、薪資、員工福利)讓您感受最深的又是什么?
            史亮:沒有存在不適應。我認為測試人員的工作環境、工作壓力、員工福利等取決與具體的項目、團隊和企業,與企業的注冊國籍并沒有直接的關系。而且,目前國內軟件業蓬勃發展,有形形色色的項目和團隊,任何外資企業所面臨的情況,都可以在中國企業中找到相似的語境。一些中國企業在全球處于領先的地位,他們的企業文化、工作方式和福利報酬都勝過外企,且領先優勢還在擴大。對于測試人員而言,應該多接觸業內同行,了解他們的工作實踐,以"他山之石可以攻玉"的心態,虛心請教。然后,將好的工作實踐"因地制宜"地修改為適合當前項目的方法,從而改進項目環境、優化工作成果。
            51Testing:看來現在國內外軟件測試行業的差異不是很大,測試人員想要出國發展還是十分可行的。那對于想要有出國發展的測試人員,您作為一個前輩對他們有些什么建議呢?
            史亮:測試專家Cem Kaner和James Bach對于測試人員的職業發展有一條忠告:"不管選擇走哪條路,都要積極追求"。測試人員并沒有被鎖定在測試上,也沒有被鎖定在任何公司或軟件行業上。他完全可以選擇改變職業發展方向并追求其他目標。一旦下定決心,就要對自己負責,通過持續地努力來推動職業生涯的發展。
            51Testing:前面聊了很多關于您在國外工作的部分,滿足了小編對于測試人員在國外工作狀態的好奇。根據小編的了解,現在很多測試新人對軟件測試的未來較為迷茫,而您在國內外都工作過很長一段時間,有相當豐富的測試經驗,您是怎么看待未來的軟件測試人員的發展趨勢?
            史亮:為了更好地討論這個問題,先介紹一個測試技術分類的參考模型。測試專家Lisa Chrispin和Janet Gregory在《敏捷軟件測試》中將測試技術劃分到如圖1所示的四個象限中。
            圖1  敏捷測試四象限
            "Q1:面向技術的(technology facing)、支持項目團隊的(supporting the team)的自動化測試,例如單元測試、組件測試等。
            "Q2:面向商業的(business facing)、支持項目團隊的自動化和手工測試,包括功能測試、樣例、用戶故事測試、原型、模擬等。
            "Q3:面向商業的、考驗產品的(critique product)的手工測試,包括探索式測試,情景測試、可用性測試、用戶驗收測試、Alpha及Beta測試等。
            "Q4:面向技術的、考驗產品的、基于工具的測試,例如性能測試、負載測試、安全性測試、屬性測試等。
            利用敏捷測試四象限,測試人員可以快速理解測試技術在軟件開發中的位置,并根據當前任務選擇合適的測試技術。不過,我并不同意Lisa Chrispin和Janet Gregory將探索式測試(exploratory testing)置于Q3象限。探索式測試是一種并行地實施測試學習、測試設計、測試執行和結果評估的測試風格。作為一種測試思維方法,它可以指導四個象限的任何一種測試技術的使用。
            目前,軟件行業高速發展,以前所未有的速度向各個產業滲透。在互聯網應用、移動應用、物聯網應用等重要領域,市場競爭日趨激烈。為了在競爭中脫穎而出,軟件項目團隊必須具備高度的機動性,能夠快速地嘗試新想法,并持續發布具有特色的產品。這要求程序員負責更多的測試活動,通過加速"編碼-測試-重構"的循環,來快速交付高質量的代碼。也就是說,程序員將承擔Q1象限(面向技術、支持項目團隊)的測試工作,以及部分其他象限的活動--以Q2象限(面向商業、支持項目團隊)的活動較為常見。
            在該趨勢下,專職測試人員的活動將向四象限的右側和上方移動,更偏向面向商業的、考驗產品的測試活動。從業務角度,測試人員的角色應該是領域專家和實際用戶,能夠以超越代碼(beyond code)眼光來考察產品的商業價值和用戶價值。從技術角度,測試人員的角色可以是黑客和技術專家,能夠在安全性、性能、穩定性等領域實施專業的、高強度的測試。
            另一個軟件研發的趨勢是DevOps,即融合研發團隊和運維團隊,由一個團隊負責整個產品開發、測試、發布、運維和更新。在此類團隊中,測試人員需要承擔部分開發和運維任務,例如分析服務端的日志、分析客戶端提交的遙測(telemetry)數據、分析用戶行為、報告服務狀態、定位產品問題、修復特定環節的錯誤、發布產品更新等。這意味著測試人員的工作不僅僅是尋找缺陷,而是通過技術調查(調查對象包括已發布的線上產品)來獲得產品信息,以持續提高產品質量。可以說,在一些項目環境中,測試人員的職責發生了變化,需要更多樣化的技能。測試人員需要積極面對變化,拓展自己的能力,以適應行業的發展。
          51Testing:您已經第二次做客我們51Testing了,上一次專訪我們聊得是探索式測試,相信很多朋友都對此印象深刻。作為探索式測試的資深人士,怎樣才能進行有效地探索式測試?另外很多優秀的軟件測試工程師都能敏銳地嗅到bug,您認為該如何訓練這方面能力?
            史亮:首先,"態度決定一切"。成為一個優秀的測試人員,我認為最重要的基礎是對項目、對自己負責任的態度。對項目負責,測試人員需要提供高質量的測試服務來幫助項目成功;對自己負責,測試人員應該以專業人員(professionals)自居,堅持專業主義(professionalism),追求精湛的技藝和卓越的成果。這需要通過日復一日的努力工作來落實,無捷徑可言。
            第二,Cem Kaner等測試專家指出"困惑是一種測試工具"。有時,軟件的表現出乎測試人員預料,但是他并不能確定這是一個缺陷。這說明測試人員對軟件的設計還有不了解的地方。他應該將此疑惑視為一個學習的機會,通過閱讀文檔、咨詢同事等方法來獲得答案。推而廣之,如果測試人員對軟件、技術或項目產生疑問,他應該感到警惕。這可能意味著他不了解業務邏輯,不知曉產品設計,不清楚實現細節。這些知識上的漏洞會導致薄弱的測試設計和嚴重的缺陷遺漏。
            負責人的測試人員不會放過任何一個疑問,在"好奇心"的指引下,他會"打破沙鍋問到底"。他會運用多種手段(周密測試、代碼分析、軟件調試、文檔閱讀、請教專家等)對問題進行研究。通過積極地測試和學習,測試人員不但可以彌補知識的漏洞,還可以發現隱藏的缺陷。
            第三,測試人員需要"刻意練習"。測試專家已經給出了許多好的建議和方法,這些想法皆來自于實踐。軟件開發專家Ralph E. Johnson 指出"從實踐中來的知識在沒有實踐之前是無法被真正理解的"(practical knowledge has to be experienced to fully understood),測試專家Cem Kaner等也認為"你不能掌握測試,除非你重新發明它"(You can't master testing unless you reinvent it)。因此,測試人員需要將學到的新技術應用于真實的測試,并認真評估其效果。通過練習、評估和反思,測試人員能夠掌握方法的原理和細節,并混入自身經驗和其他技術,以演化出新的方法。堅持這樣的研究和創新將幫助測試人員走上精通之路。
            51Testing:許多剛從事測試的新人往往會在工作的過程中發現自己的很多不足,想要提高自己,在您看來,測試人員應如何提高自己的測試思維和測試技術?
            史亮:前面兩個問題的回答對于本問題有參考價值。在這里,我補充說明一個測試人員容易忽略的要點:提高測試技術的根本目標是為了更有效的測試,在許多情況下,測試效果(測試技術的實施效果)決于測試人員對軟件和項目的理解。
            我曾經長期測試一個網絡應用。當我離開這個項目時,測試經理安排一個測試員工來接替我。他剛剛入職,對被測軟件和業務領域都不了解,在工作中遇到了許多困難,我幫助他解決了一系列問題。作為一個測試工程師,我的工作效率更高,主要原因包括:
            " 我理解產品,知道它的業務目標,了解它通過什么方法去實現目標。因此,我能夠快速地制定測試方案。
            " 我理解用戶的期望,知道哪些功能絕對不能出錯,需要仔細測試。我也知道哪些功能允許一些瑕疵,即便出錯,也可以在三個月之后發布的下一個版本中修復。因此,我能夠更好地分配測試時間。
            " 我理解產品的架構,閱讀過大部分模塊源代碼,知道哪些模塊容易出現哪些缺陷。因此,我可以針對不同的模塊采用有針對性的測試策略。
            " 我曾經嘗試自動化測試用戶界面,但是發現此類自動化測試很不穩定,需要很高的維護代價,卻不能發現錯誤。于是,我只為Web服務編寫自動化測試用例,用手工測試來檢查用戶界面。因此,我回避了浪費時間卻沒有收益的任務。
            " 我了解產品元素和項目團隊。當出現缺陷時,我知道如何閱讀系統日志發掘蛛絲馬跡;當我遇到困難時,我知道向哪位程序員或測試人員求助。因此,我可以深入挖掘并快速推進。
            " 我在原先的團隊工作了很長的時間,與同事們保持了良好的關系。當我提出一些可測試性的建議時,比較容易受到程序員的支持。
            從以上幾點不難看出,我能夠更有效地測試,其主要原因不是我掌握更多的測試技術,而是我更了解軟件產品、業務領域和項目環境。通過逐點分析,可以得到如下啟示。
            " 產品是一種解決方案,如果沒有解決問題,它就是無用的。測試人員需要了解軟件產品和業務領域,才能設計有效的測試。
            " 測試是一種信息服務,要了解服務對象(通常最重要的服務對象是用戶和項目經理)的需求。如果用戶不能容忍某些錯誤,測試人員就需要仔細測試相關功能;如果用戶對一些瑕疵并不在意,測試人員就不必在此花費更多的時間。只有了解服務對象的優先級,才能更好地設定測試工作的優先級。
            " 不同的模塊采用不同的技術,擁有不同的典型錯誤。只有了解軟件實現,才能設計差異化且有針對性的測試用例。
            " 測試設計可能包含錯誤,測試人員需要從錯誤中吸取經驗和教訓。避免一些已知的錯誤,會提高測試效率。
            " 當測試工作遇到困難時,測試人員需要知道在哪里尋找信息。了解產品能夠提供的信息、了解哪位同事知道更多內幕,會節省時間。
            " "人脈"有時候會極大地提高測試人員的工作效率,測試人員需要和程序員和測試同事保持良好的關系。達成協作關系的關鍵之一是測試人員能夠為同事們提供高質量的信息服務。
            " 在職業生涯中,測試人員總是會遇到新的軟件、項目和團隊。他應該培養一種好的工作風格,以求快速地理解產品和項目。
            實施高效的測試需要很多條件。熟練地掌握測試技術是一個很重要的因素,但很少會是決定性的因素。只有充分地掌握軟件產品和項目環境,測試技術才能找到大放光彩的舞臺。

           51Testing:想要提高測試技術,書籍是必不可少的朋友,作為探索式測試的忠實實踐者,您能給我們的會員推薦幾本相關書籍嗎?
            史亮:探索式測試是一個內涵豐富的主題,感興趣的測試人員可以從以下書籍入手。
            " Cem Kaner, James Bach, Bret Pettichord, 《軟件測試經驗與教訓》(Lessons Learned in Software Testing:A Context-Driven Approach)。該書是語境驅動測試的經典著作,充滿對軟件測試的真知灼見,是探索式測試者案頭必備。
            " 史亮,高翔,《探索式測試實踐之路》。該書由我與淘寶資深測試工程師高翔合著,系統地總結了現有的探索式測試實踐,并納入了我們的經驗和反思。探索式測試大師James Bach對此書予以了肯定:This is the first book on exploratory testing, in any language, that summarizes the published work in the field。
            " 史亮,《軟件測試實戰》。我本人是探索式測試的忠實實踐者,該書可視為"一個探索式測試者的自我總結"。全書雖然沒有強調名詞"探索式測試",但是探索式測試的核心精神(將測試學習、測試設計、測試執行、測試結果評估作為相互支持的活動來并行實施)貫穿全書。
            " 我和高翔在《探索式測試實踐之路》的附錄B提供了一批推薦讀物,供讀者參考。
            51Testing:本次訪談即將接近尾聲,再問最后一個問題,您以后會選擇繼續長期留在國外發展還是回國發展呢?
            史亮:我目前還在持續評估自己的職業發展,尚未做出長遠的規劃。
            51Testing:由于時間關系,本次訪談正式結束,非常感謝史亮老師抽出寶貴時間參加我們的訪談,祝您在國外工作一切順利!
            史亮:謝謝,也祝51Testing越辦越好!
           版權聲明:51Testing軟件測試網原創出品,轉載時請務必以超鏈接形式標明文章原始出處、作者信息和本聲明,否則將追究法律責任。

          posted @ 2014-08-26 09:41 順其自然EVO 閱讀(192) | 評論 (0)編輯 收藏

          僅列出標題
          共394頁: First 上一頁 58 59 60 61 62 63 64 65 66 下一頁 Last 
          <2025年7月>
          293012345
          6789101112
          13141516171819
          20212223242526
          272829303112
          3456789

          導航

          統計

          常用鏈接

          留言簿(55)

          隨筆分類

          隨筆檔案

          文章分類

          文章檔案

          搜索

          最新評論

          閱讀排行榜

          評論排行榜

          主站蜘蛛池模板: 永宁县| 曲靖市| 察雅县| 互助| 奉节县| 嘉兴市| 津市市| 天等县| 金沙县| 湘潭市| 崇左市| 宜城市| 安塞县| 天全县| 平南县| 登封市| 东辽县| 彭阳县| 鱼台县| 柘荣县| 甘德县| 正阳县| 铜山县| 南溪县| 庆元县| 江孜县| 苏尼特左旗| 济源市| 特克斯县| 肇庆市| 牙克石市| 高州市| 琼结县| 恭城| 广平县| 莆田市| 上杭县| 海丰县| 桐柏县| 滕州市| 南京市|