mockserver的技術實現
目前,筆者已經用python實現了乙個基於socket介面的mock server並在測試中進行了一定的應用,實現中利用了一些python的語言特性、一點rpc技術和一點dsl的技巧。
乙個case
下面先看乙個實際的case,case加入了許額外的注釋,以解釋這段**的意義 (case的格式為一種可嵌入python**的dsl指令碼)
case ds返回結果異常測試
begin
group_id=55
__exec__=begin
python mock_execute(r.strip())
python request(host='',port=$,=$,=$,time=$,='',cached=$,cache_flag='')
endcase 測試 1
begin
mock_data=begin
mock.on(
large_than(192),
).do(
send_back(
am_head_t(1,0,(c_uint32*2)(100,100),sizeof(ds_qres_head_t)+12+32),
ds_qres_head_t(0,1,1,32,12,),
2,4,
"show",
47,3,4,12,
123,"hello,world!"
),clear_buf(),
clear_mock(),
)end
endcase 測試 2
begin
…………
end……
…………
……end
上面的**中,request的函式的功能是將各引數拼裝成乙個http請求傳送給被測系統並接收返回的結果。而mock_execute也就是對 mock server的呼叫了。
下面就看看這個mock server是如讓上面的case得以執行的
核心**
首先看mock server中的主體**,該**基於python中的threadingtcpserver,如下:
self.stop self.server.stop:buf=self.sock.recv(4096)
buf:
time.sleep(0.1)
self.buffer+=buf
mock mockrequesthandler.mocks:
mock(self):
這段**可以看作是程式的主迴圈,它不斷的從socket讀取**,然後呼叫mock物件,觸發其中定義的行為。乙個mock物件定義了乙個行為,程式充許一次定義的多個mock,也有使得程式可以模擬比較複雜的行為了。
下面再看看mock物件裡面是如何定義的
(x,y:x y,
( f:f(handler),self.on_list),
true
):'',self.on_list,self.do_list
( f:f(handler),self.do_list)
true
false
這裡用到了一點兒函式式程式設計的技巧,在on_list中儲存了當前mock的觸發條件,do_list中則儲存了當前mock要執行的操作,這段**的就意思就是當所有的觸發條件都滿足時,就順序執行操作列表的中的操作,否則就退出。
上面兩段**就構成了mock server的核心邏輯。
條件與結果
接下來我們看看on_list和do_list裡面到底是什麼,以前面的case中用到的large_than和send_back為例,它們的原始定義如下所示:
@mock_actionlarge_than(handler,size):
(handler.buffer)>=size
@mock_action
send_back(handler,data):
handler.sock.sendall(data)
可以看到,它們的第一引數都是handler,它代表了當前請求處理器的例項,包含以下幾個基本的成員:
對照 核心** 中的主迴圈,這裡的handler就是迴圈中的self,這樣就不難明白這幾個成員的作用了。
在on_list和do_list中儲存就是對這些函式的「間接」引用。那什麼是間接引用呢?
回頭看前面cae中的**:
mock.on(large_than(192),
).do(
send_back(
am_head_t( …………)
)
看以看到這裡並沒有給large_than和send_back傳入handler引數,而且,熟悉python語法的人也會發現,這是對函式的呼叫,而不是對函式物件本身的引用,最終on方法得到的引數應該是large_than執行完的結果,不是large_than這個函式物件。說了這麼多,好像很混亂的樣子,其實密秘就在
@mock_action中,這個是python中的函式修飾器,它本身也是乙個函式,接受乙個函式物件為引數,返回乙個新的函式物件,來看看mock_action的定義:
mock_action(f):它實際上對是原始的函式進行一次封裝,有點類似函式式程式設計中的高階函式,簡單來說就是將開始那段函式定義的**等價於下面的**:factor(*args):
action= h:f(h,*args)
action.__name__=f.__name__+''
action
factor.is_mock_action=true
factor.__name__=f.__name__+''
factor
large_than(size):當然也可以在定義mock行為時寫成這樣:large_than_func(handler):
(handler.buffer)>=size
large_than_func
send_back(data):
send_back_func(handler):
handler.sock.sendall(data)
send_back_func
mock.on(不過這個就有點兒太難看了。handler:large_than(handler,192)
).do(
handler:send_back(handler, …… )
)
行為描述
前面說了好多mock裡存什麼,現看看這此東西是怎麼存進去的,來一段更有代表性的**:
mock.on(每一組on|do呼叫都定義了乙個新的mock,上面的**中定義了三個mock,那麼如何能保證on|do能成對出現,且不符合約定時能丟擲異常呢?any_package(),
large_than(32),
).do(
send_back(''),
clear_buf(),
).on(
got(''),
).do(
close_sock(),
).on(
got(''),
).do(
stop_server(),
)
其實上面的**可看作是一段dsl的**,我們在python的語法基礎上,新增了on/do兩個關鍵字,並做了一定的語法限定。而在**中實現on和 do時也進行相應的處理,以保證語法約定的正確性。
通過上面的**就限制了do必須出現on後面,否則會提示mock物件不支援do方法。同時如果只有on沒有do,也不會建立新的mock。
遠端呼叫
現在,我們的mock server已經可以啟動執行了,但必須且只能在啟動時指定mock行為,也就是說還不能動態更新配置。
接下來就該rpc登場了,rpc是遠端過程呼叫的簡稱,這裡的遠端指的是不同的程序,可能是同一臺機器上的,也可能是位於不同機器上的,它們之間可以通過某種pic(程序間通訊)協議傳遞資訊,比如socket。而rpc就是對pic協議的再封裝,把資訊傳送/接收的過程變成更簡單易用的函式呼叫過程。
本例中使用python的第三方擴充套件庫rpyc來實現rpc,這樣就可以在case中動態的修改mock server的形為了。
execute (code,service_name=''):conn=get_online_connectiones(service_name)[-1]
conn.root.execute(code)
=='':
execute(r)
()
在最開始的case中的mock_exectue函式,實際上就是對這裡的execute的再包裝而已。
綜述 總結一下我們所實現的這個mock server的特點:
相比之傳統定義上的stub server, mock server拋棄了死板的配置檔案,將要行為描述與介面實現分離,更利於**的復用,進一步簡化樁程式的開發成本。
(全文完)
【本文首發於:
效能測試的思想
幾個主要的術語 效能測試的方法 1 驗收效能測試 通過模擬生產執行的業務壓力量和使用場景組合,測試系統的效能是否滿足生產效能要求,這種測試方法就是要在特定的執行條件下驗證系統的能力狀態。2 負載測試 在被測系統上不斷增加壓力,直到效能指標 如響應時間 超過預定指標或者某種資源使用已經達到飽和狀態。3...
乙個簡單的mock server
在前後端分離的專案中,前端無需等後端介面提供了才除錯,後端無需等第三方介面提供了才除錯,基於 契約 可以通過mock server實現除錯,下面是乙個簡單的mock server,通過python的flask框架實現,獲取所有使用者 獲取指定使用者 非法字元 改進mock test.py from ...
測試總體思想
1.對於需求有更改的這種情況來說 測試計畫的編制是為了框定測試範圍。第一步要整理好需求中提到的點 第二步要把需求修改的關聯到的點圈定出來。在測試用例的設計中優先順序應該是這樣的 i.業務流程的測試 畫出業務流程圖。在這個過程中如果能附帶些功能點就帶上 ii.功能用例 iii.公共用例 2.對於完全新...