Erlang 21 - 14. Common Test Hooks

14 आम टेस्ट हुक




erlang

14 आम टेस्ट हुक

14.1 सामान्य

कॉमन टेस्ट हुक (CTH) फ्रेमवर्क सभी टेस्ट सूट कॉल के पहले और बाद Common Test के डिफ़ॉल्ट व्यवहार के विस्तार की अनुमति देता है। CTH, Common Test उपयोगकर्ताओं को बर्ताव से अलग करने की अनुमति देते हैं, जो लाइब्रेरी कॉल के साथ सभी टेस्ट सुइट्स को लैटर किए बिना कई टेस्ट सूट के लिए आम है। इसका उपयोग बाहरी प्रणालियों को लॉगिंग, शुरू करने और निगरानी के लिए किया जा सकता है, परीक्षणों द्वारा आवश्यक सी फाइलों का निर्माण, और इसी तरह।

संक्षेप में, CTH आपको निम्नलिखित कार्य करने की अनुमति देता है:

  • प्रत्येक सुइट कॉन्फ़िगरेशन कॉल से पहले रनटाइम कॉन्फ़िगरेशन में हेरफेर करें।
  • सभी सुइट कॉन्फ़िगरेशन कॉल की वापसी में हेरफेर करें, और विस्तार में, खुद परीक्षणों का परिणाम।

निम्नलिखित अनुभागों का वर्णन है कि CTH का उपयोग कैसे किया जाता है, जब उन्हें चलाया जाता है, और CTH में परीक्षा परिणामों में हेरफेर कैसे किया जाता है।

चेतावनी

CTH के भीतर निष्पादित करते समय, सभी समय-सीमाएँ बंद हो जाती हैं। इसलिए यदि आपका CTH कभी नहीं लौटता है, तो संपूर्ण परीक्षण रन ठप हो जाता है।

14.2 CTH की स्थापना

आपके टेस्ट रन में CTH को कई तरीकों से स्थापित किया जा सकता है। आप इसे सभी परीक्षणों के लिए एक रन में, विशिष्ट परीक्षण सूट के लिए और एक परीक्षण सूट के भीतर विशिष्ट समूहों के लिए कर सकते हैं। यदि आप चाहते हैं कि CTH आपके टेस्ट रन के भीतर सभी टेस्ट सूट में मौजूद हो, तो इसे पूरा करने के तीन तरीके हैं, जो निम्नानुसार हैं:

  • Add -ct_hooks को ct_run तर्क के रूप में। इस पद्धति का उपयोग करके कई CTH जोड़ने के लिए, उन्हें कीवर्ड का उपयोग करके एक दूसरे के साथ जोड़ें and वह है, ct_run -ct_hooks cth1 [{debug,true}] and cth2 ...
  • अपने Test Specification टैग ct_hooks जोड़ें।
  • ct:run_test/1 पर अपनी कॉल में टैग ct_hooks जोड़ें।

CTH को एक परीक्षण सूट के भीतर भी जोड़ा जा सकता है। यह suite/0 , init_per_suite/1 , या init_per_group/2 से कॉन्फ़िगरेशन सूची में {ct_hooks,[CTH]} को वापस करके किया जाता है।

इस स्थिति में, CTH या तो केवल CTH का मॉड्यूल नाम या मॉड्यूल नाम और प्रारंभिक तर्कों के साथ एक ट्यूपल हो सकता है, और वैकल्पिक रूप से CTH की हुक प्राथमिकता हो सकती है। उदाहरण के लिए, निम्नलिखित में से एक:

  • {ct_hooks,[my_cth_module]}
  • {ct_hooks,[{my_cth_module,[{debug,true}]}]}
  • {ct_hooks,[{my_cth_module,[{debug,true}],500}]}

ओवरराइडिंग CTHs

डिफ़ॉल्ट रूप से, CTH की प्रत्येक स्थापना सक्रिय होने का एक नया उदाहरण देती है। यदि आप सुइट सूचना फ़ंक्शन में रहते हुए भी CTH को परीक्षण विनिर्देशों में ओवरराइड करना चाहते हैं तो यह समस्या पैदा कर सकता है। इस समस्या को हल करने के लिए id/1 कॉलबैक मौजूद है। दोनों स्थानों पर एक ही id वापस करके, Common Test जानता है कि यह CTH पहले से इंस्टॉल है और इसे फिर से इंस्टॉल करने का प्रयास नहीं करता है।

CTH निष्पादन आदेश

डिफ़ॉल्ट रूप से, स्थापित प्रत्येक CTH को इस क्रम में निष्पादित किया जाता है कि वे init कॉल के लिए इंस्टॉल किए जाते हैं, और फिर अंत कॉल के लिए उलट हो जाते हैं। यह हमेशा वांछित नहीं होता है, इसलिए Common Test उपयोगकर्ता को प्रत्येक हुक के लिए प्राथमिकता निर्दिष्ट करने की अनुमति देता है। प्राथमिकता या तो सीटीएच फ़ंक्शन init/2 या हुक स्थापित करते समय निर्दिष्ट की जा सकती है। स्थापना में निर्दिष्ट प्राथमिकता CTH द्वारा दी गई प्राथमिकता से आगे निकल जाती है।

14.3 CTH स्कोप

एक बार जब CTH एक निश्चित परीक्षण रन में स्थापित हो जाता है तो यह तब तक बना रहता है जब तक इसका दायरा समाप्त नहीं हो जाता। CTH का दायरा इस बात पर निर्भर करता है कि इसे कब स्थापित किया जाए, निम्न तालिका देखें। फंक्शन init/2 को स्कोप की शुरुआत में कहा जाता है और फंक्शन terminate/1 तब होता है जब स्कोप खत्म होता है।

में स्थापित किया गया CTH का दायरा पहले शुरू होता है CTH का दायरा बाद में समाप्त होता है
ct_run पहला टेस्ट सूट चलाया जाना है अंतिम परीक्षण सूट चलाया गया है
ct:run_test/1 पहला परीक्षण सूट चलाया जाता है अंतिम परीक्षण सूट चलाया गया है
Test Specification पहला परीक्षण सूट चलाया जाता है अंतिम परीक्षण सूट चलाया गया है
suite/0 pre_init_per_suite/3 कहा जाता है post_end_per_suite/4 को उस टेस्ट सूट के लिए बुलाया गया है
init_per_suite/1 post_init_per_suite/4 कहा जाता है post_end_per_suite/4 को उस टेस्ट सूट के लिए बुलाया गया है
init_per_group/2 post_init_per_group/5 कहा जाता है उस समूह के लिए post_end_per_group/5 कहा जाता है

तालिका 14.1: CTH का दायरा

CTH प्रोसेस और टेबल्स

CTH को सामान्य परीक्षण सूट के रूप में एक ही प्रक्रिया के साथ चलाया जाता है, अर्थात, एक अलग प्रक्रिया init_per_suite हुक और फिर init_per_group या per_testcase हुक निष्पादित करती है। इसलिए यदि आप CTH में किसी प्रक्रिया को स्पॉन करना चाहते हैं, तो आप CTH प्रक्रिया के साथ लिंक नहीं कर सकते, क्योंकि यह पोस्ट हुक समाप्त होने के बाद बाहर निकलता है। इसके अलावा, यदि आपको किसी कारण से अपने CTH के साथ ETS तालिका की आवश्यकता है, तो आपको एक प्रक्रिया को अपनाना होगा जो इसे संभालती है।

बाहरी कॉन्फ़िगरेशन डेटा और लॉगिंग

CTH में कॉन्फ़िगरेशन डेटा मूल्यों को ct:get_config/1,2,3 कहकर पढ़ा जा सकता है (जैसा कि आवश्यक Requiring and Reading Configuration Data )। प्रश्न में कॉन्फ़िगरेशन चर हमेशा की तरह, पहले, एक सूट द्वारा आवश्यक हो गया है-, समूह- या परीक्षण मामले की जानकारी फ़ंक्शन, या फ़ंक्शन ct:require/1/2 द्वारा ct:require/1/2 । उत्तरार्द्ध का उपयोग सीटी हुक कार्यों में भी किया जा सकता है।

सीटी हुक फ़ंक्शंस लॉग इन फ़ाइलों की जानकारी प्रिंट करने के लिए, या सुइट अवलोकन पृष्ठ में टिप्पणियों को जोड़ने के लिए ct इंटरफ़ेस में किसी भी लॉगिंग फ़ंक्शन को कॉल कर सकते हैं।

14.4 मैनीपुलेटिंग टेस्ट

CTH के माध्यम से परीक्षण और कॉन्फ़िगरेशन फ़ंक्शन के परिणामों में हेरफेर किया जा सकता है। CTH के साथ ऐसा करने का मुख्य उद्देश्य सामान्य पैटर्न को टेस्ट सूट से अलग करने की अनुमति देना है और किसी भी कोड को दोहराए बिना कई टेस्ट सूट पर लागू किया गया है। CTH के सभी कॉलबैक फ़ंक्शन उसके बाद वर्णित एक सामान्य इंटरफ़ेस का अनुसरण करते हैं।

Common Test हमेशा सभी उपलब्ध हुक फ़ंक्शंस को कॉल करता है, यहां तक ​​कि कॉन्फ़िगरेशन कार्यों के लिए पूर्व और बाद के हुक भी जो सूट में लागू नहीं होते हैं। उदाहरण के लिए, pre_init_per_suite(x_SUITE, ...) और post_init_per_suite(x_SUITE, ...) को टेस्ट सूट x_SUITE लिए कहा जाता है, भले ही यह init_per_suite/1 निर्यात न करे। इस सुविधा के साथ हुक का उपयोग कॉन्फ़िगरेशन कमियां के रूप में किया जा सकता है, और सभी कॉन्फ़िगरेशन फ़ंक्शन को हुक फ़ंक्शंस से बदला जा सकता है।

प्री हुक

CTH में, व्यवहार निम्न कार्यों से पहले झुका जा सकता है:

यह CTH फ़ंक्शन में किया जाता है जिसे pre_<name of function> कहा जाता है। ये फ़ंक्शन तर्क Name , Name (समूह या परीक्षण मामले का नाम, यदि लागू हो), Config और CTHState । CTH फ़ंक्शन का रिटर्न मान हमेशा सूट / समूह / परीक्षण और एक अद्यतन CTHState लिए एक परिणाम का एक संयोजन है।

परीक्षण सूट को निष्पादित करने के लिए जारी रखने के लिए, कॉन्फ़िगरेशन सूची को लौटाएं जिसे आप परिणाम के रूप में उपयोग करना चाहते हैं।

pre_end_per_testcase/4 को छोड़कर सभी प्री हुक, स्किप या फेल के साथ एक टपल लौटाकर परीक्षण को fail या fail कर fail , और परिणाम के रूप में एक कारण।

उदाहरण:

pre_init_per_suite(SuiteName, Config, CTHState) ->
  case db:connect() of
    {error,_Reason} ->
      {{fail, "Could not connect to DB"}, CTHState};
    {ok, Handle} ->
      {[{db_handle, Handle} | Config], CTHState#state{ handle = Handle }}
  end.
ध्यान दें

यदि आप कई CTH का उपयोग करते हैं, तो रिटर्न टुपल का पहला भाग अगले CTH के लिए इनपुट के रूप में उपयोग किया जाता है। इसलिए पिछले उदाहरण में अगला CTH दूसरे पैरामीटर के रूप में {fail,Reason} प्राप्त कर सकता है। यदि आपके पास कई CTH इंटरेक्टिंग हैं, तो प्रत्येक CTH को fail न होने दें या skip । इसके बजाय, लौटें कि एक कार्रवाई को Config सूची के माध्यम से लिया जाना है और एक CTH को लागू करना है, जो अंत में, सही कार्रवाई करता है।

पोस्ट हुक

CTH में, व्यवहार को निम्न कार्यों के बाद झुका दिया जा सकता है:

यह CTH फ़ंक्शन में किया जाता है जिसे post_<name of function> कहा जाता है। ये फ़ंक्शन तर्क Name , Name (समूह या परीक्षण केस का नाम, यदि लागू हो), Config , Return और CTHState । इस मामले में Config वही Config जैसा टेस्‍टकेस को कहा जाता है। Return टेस्टकेस द्वारा दिया गया मान है। यदि दुर्घटनाग्रस्त होने से टेस्टकेस विफल हो जाता है, तो Return {'EXIT',{{Error,Reason},Stacktrace}}

CTH फ़ंक्शन का रिटर्न मान हमेशा सूट / समूह / परीक्षण और एक अद्यतन CTHState लिए एक परिणाम का एक संयोजन है। यदि आप कॉलबैक को परीक्षण के परिणाम को प्रभावित नहीं करना चाहते हैं, तो Return डेटा Return क्योंकि यह CTH को दिया गया है। आप परीक्षा परिणाम को संशोधित भी कर सकते हैं। एलिमेंट सूची को तत्व tc_status साथ हटाकर, आप एक परीक्षण विफलता से उबर सकते हैं। जैसा कि सभी पूर्व हुक में होता है, पोस्ट हुक में परीक्षण मामले को विफल / छोड़ना भी संभव है।

उदाहरण:

post_end_per_testcase(_Suite, _TC, Config, {'EXIT',{_,_}}, CTHState) ->
  case db:check_consistency() of
    true ->
      %% DB is good, pass the test.
      {proplists:delete(tc_status, Config), CTHState};
    false ->
      %% DB is not good, mark as skipped instead of failing
      {{skip, "DB is inconsisten!"}, CTHState}
  end;
post_end_per_testcase(_Suite, _TC, Config, Return, CTHState) ->
  %% Do nothing if tc does not crash.
  {Return, CTHState}.
ध्यान दें

केवल एक अंतिम उपाय CTHs का उपयोग करके एक टेस्टकेस की विफलता से उबरें। यदि गलत तरीके से उपयोग किया जाता है, तो यह निर्धारित करना बहुत मुश्किल हो सकता है कि कौन से परीक्षण पास होते हैं या टेस्ट रन में असफल होते हैं।

स्किप और फेल हुक

किसी भी पोस्ट हुक को सभी स्थापित CTH के लिए निष्पादित करने के बाद, on_tc_fail या on_tc_skip को बुलाया जाता है, यदि क्रमशः on_tc_skip विफल हुआ या छोड़ दिया गया था। आप इस बिंदु पर किसी भी आगे परीक्षण के परिणाम को प्रभावित नहीं कर सकते।

14.5 कॉमन टेस्ट के साथ बाहरी उपयोगकर्ता अनुप्रयोगों को सिंक्रनाइज़ करना

CTH का उपयोग बाहरी उपयोगकर्ता अनुप्रयोगों के साथ परीक्षण रन को सिंक्रनाइज़ करने के लिए किया जा सकता है। Init फ़ंक्शन, उदाहरण के लिए, शुरू और / या एक एप्लिकेशन के साथ संवाद कर सकता है जिसका उद्देश्य आगामी टेस्ट रन के लिए SUT तैयार करना है, या टेस्ट रन के दौरान टेस्ट डेटा को बचाने के लिए डेटाबेस को इनिशियलाइज़ करना है। समाप्त फ़ंक्शन समान रूप से परीक्षण चलाने के बाद SUT को रीसेट करने के लिए इस तरह के एक आवेदन का आदेश दे सकता है, और / या सक्रिय सत्रों को समाप्त करने और समाप्त करने के लिए एप्लिकेशन को बता सकता है। किसी भी सिस्टम त्रुटि या init- या समाप्ति चरण के दौरान उत्पन्न प्रगति रिपोर्ट Pre- and Post Test I/O Log में सहेजे जाते हैं। (यह ct:log/2 और ct:pal/2 ) के साथ किए गए किसी भी प्रिंटआउट के लिए भी सही है।

यह सुनिश्चित करने के लिए कि Common Test परीक्षण निष्पादित करना शुरू नहीं करता है, या अपनी लॉग फ़ाइलों को बंद कर देता है और बंद हो जाता है, इससे पहले कि बाहरी एप्लिकेशन इसके लिए तैयार हो, Common Test को एप्लिकेशन के साथ सिंक्रनाइज़ किया जा सकता है। स्टार्टअप और शटडाउन के दौरान, Common Test को निलंबित किया जा सकता है, बस एक CTH द्वारा init- या समाप्त फ़ंक्शन में receive अभिव्यक्ति का मूल्यांकन किया जाता है। मैक्रोज़ ?CT_HOOK_INIT_PROCESS (हुक ?CT_HOOK_TERMINATE_PROCESS फ़ंक्शन को निष्पादित करने की प्रक्रिया) और ?CT_HOOK_TERMINATE_PROCESS (हुक समाप्ति फ़ंक्शन को निष्पादित करने वाली प्रक्रिया) प्रत्येक को संदेश भेजने के लिए सही Common Test प्रक्रिया का नाम निर्दिष्ट करता है। यह receive से लौटने के लिए किया जाता है। ये मैक्रोज़ ct.hrl में परिभाषित किए ct.hrl

14.6 उदाहरण CTH

निम्नलिखित CTH file:consult/1 द्वारा पार्स करने योग्य प्रारूप में परीक्षण चलाने के बारे में जानकारी लॉग करता है file:consult/1 (कर्नेल में):

 %%% Common Test Example Common Test Hook module.
 -module(example_cth).

 %% Callbacks
 -export([id/1]).
 -export([init/2]).

 -export([pre_init_per_suite/3]).
 -export([post_init_per_suite/4]).
 -export([pre_end_per_suite/3]).
 -export([post_end_per_suite/4]).

 -export([pre_init_per_group/4]).
 -export([post_init_per_group/5]).
 -export([pre_end_per_group/4]).
 -export([post_end_per_group/5]).

 -export([pre_init_per_testcase/4]).
 -export([post_init_per_testcase/5]).
 -export([pre_end_per_testcase/4]).
 -export([post_end_per_testcase/5]).

 -export([on_tc_fail/4]).
 -export([on_tc_skip/4]).

 -export([terminate/1]).

 -record(state, { file_handle, total, suite_total, ts, tcs, data }).

 %% Return a unique id for this CTH.
 id(Opts) ->
   proplists:get_value(filename, Opts, "/tmp/file.log").

 %% Always called before any other callback function. Use this to initiate
 %% any common state. 
 init(Id, Opts) ->
     {ok,D} = file:open(Id,[write]),
     {ok, #state{ file_handle = D, total = 0, data = [] }}.

 %% Called before init_per_suite is called.
 pre_init_per_suite(Suite,Config,State) ->
     {Config, State#state{ suite_total = 0, tcs = [] }}.

 %% Called after init_per_suite.
 post_init_per_suite(Suite,Config,Return,State) ->
     {Return, State}.

 %% Called before end_per_suite.
 pre_end_per_suite(Suite,Config,State) ->
     {Config, State}.

 %% Called after end_per_suite.
 post_end_per_suite(Suite,Config,Return,State) ->
     Data = {suites, Suite, State#state.suite_total, lists:reverse(State#state.tcs)},
     {Return, State#state{ data = [Data | State#state.data] ,
                           total = State#state.total + State#state.suite_total } }.

 %% Called before each init_per_group.
 pre_init_per_group(Suite,Group,Config,State) ->
     {Config, State}.

 %% Called after each init_per_group.
 post_init_per_group(Suite,Group,Config,Return,State) ->
     {Return, State}.

 %% Called before each end_per_group.
 pre_end_per_group(Suite,Group,Config,State) ->
     {Config, State}.

 %% Called after each end_per_group.
 post_end_per_group(Suite,Group,Config,Return,State) ->
     {Return, State}.

 %% Called before each init_per_testcase.
 pre_init_per_testcase(Suite,TC,Config,State) ->
     {Config, State#state{ ts = now(), total = State#state.suite_total + 1 } }.

 %% Called after each init_per_testcase (immediately before the test case).
 post_init_per_testcase(Suite,TC,Config,Return,State) ->
     {Return, State}

%% Called before each end_per_testcase (immediately after the test case).
 pre_end_per_testcase(Suite,TC,Config,State) ->
     {Config, State}.

 %% Called after each end_per_testcase.
 post_end_per_testcase(Suite,TC,Config,Return,State) ->
     TCInfo = {testcase, Suite, TC, Return, timer:now_diff(now(), State#state.ts)},
     {Return, State#state{ ts = undefined, tcs = [TCInfo | State#state.tcs] } }.

 %% Called after post_init_per_suite, post_end_per_suite, post_init_per_group,
 %% post_end_per_group and post_end_per_testcase if the suite, group or test case failed.
 on_tc_fail(Suite, TC, Reason, State) ->
     State.

 %% Called when a test case is skipped by either user action
 %% or due to an init function failing.  
 on_tc_skip(Suite, TC, Reason, State) ->
     State.

 %% Called when the scope of the CTH is done
 terminate(State) ->
     io:format(State#state.file_handle, "~p.~n",
                [{test_run, State#state.total, State#state.data}]),
     file:close(State#state.file_handle),
     ok.

14.7 CTH में बिल्ट-इन

Common Test कुछ सामान्य-उद्देश्य CTH के साथ दिया जाता है जिसे उपयोगकर्ता द्वारा सामान्य परीक्षण कार्यक्षमता प्रदान करने के लिए सक्षम किया जा सकता है। इनमें से कुछ CTH को डिफ़ॉल्ट रूप से सक्षम किया जाता है जब common_test को चलाना शुरू किया जाता है। कमांड लाइन पर या परीक्षण विनिर्देश में false करने के लिए enable_builtin_hooks सेट करके उन्हें अक्षम किया जा सकता है। निम्नलिखित दो CTH Common Test साथ दिए गए हैं:

cth_log_redirect

में निर्मित

सामान्य रूप से डिफ़ॉल्ट लकड़हारा हैंडलर द्वारा मुद्रित किए जाने वाले सभी लॉग ईवेंट को कैप्चर करता है, और उन्हें वर्तमान परीक्षण केस लॉग में प्रिंट करता है। यदि कोई घटना परीक्षण के मामले से जुड़ी नहीं हो सकती है, तो वह Common Test फ्रेमवर्क लॉग में छपी है। यह समानांतर मामलों में चल रहे परीक्षण मामलों और बीच-बीच में होने वाले मामलों के लिए होता है। आप सामान्य एसएएसएल तंत्र का उपयोग करके SASL रिपोर्ट के स्तर को कॉन्फ़िगर कर सकते हैं।

cth_surefire

बिल्ट-इन नहीं

सभी परीक्षण परिणामों को कैप्चर करता है और उन्हें फ़ाइल में अचूक XML के रूप में आउटपुट करता है। बनाई गई फ़ाइल डिफ़ॉल्ट रूप से junit_report.xml । फ़ाइल का नाम इस हुक के लिए विकल्प path सेट करके बदला जा सकता है, उदाहरण के लिए:

-ct_hooks cth_surefire [{path,"/tmp/report.xml"}]

यदि विकल्प url_base सेट है, तो url नामक एक अतिरिक्त विशेषता प्रत्येक testsuite में जोड़ा जाता है और XML तत्व का testsuite है। मूल्य उदाहरण के लिए, क्रमशः url_base और परीक्षण सूट या टेस्ट केस लॉग के सापेक्ष पथ से निर्मित होता है:

-ct_hooks cth_surefire [{url_base, "http://myserver.com/"}]

के समान एक URL विशेषता मान देता है

"http://myserver.com/[email protected]_11.19.39/ x86_64-unknown-linux-gnu.my_test.logs/run.2012-12-12_11.19.39/suite.log.html"

उदाहरण के लिए, ज़ेनकिंस द्वारा परीक्षण परिणाम प्रदर्शित करने के लिए अचूक XML का उपयोग किया जा सकता है।