Erlang 21 - 13. Dependencies between Test Cases and Suites

13 टेस्ट केस और सूट के बीच निर्भरता




erlang

13 टेस्ट केस और सूट के बीच निर्भरता

13.1 सामान्य

परीक्षण सूट बनाते समय, परीक्षण मामलों के बीच निर्भरता नहीं बनाने के लिए दृढ़ता से अनुशंसा की जाती है, अर्थात्, परीक्षण मामलों को पिछले परीक्षण मामलों के परिणाम पर निर्भर करते हैं। इसके विभिन्न कारण हैं, जैसे कि, निम्नलिखित:

  • यह व्यक्तिगत रूप से परीक्षण मामलों को चलाने के लिए असंभव बनाता है।
  • यह एक अलग क्रम में परीक्षण मामलों को चलाने के लिए असंभव बनाता है।
  • यह डिबगिंग को कठिन बनाता है (क्योंकि एक असफलता की तुलना में एक अलग परीक्षण मामले में एक समस्या का परिणाम हो सकता है)।
  • निर्भरता घोषित करने के लिए कोई अच्छा और स्पष्ट तरीका नहीं है, इसलिए टेस्ट सूट कोड और टेस्ट लॉग में इन्हें देखना और समझना मुश्किल हो सकता है।
  • परीक्षण के मामले पर निर्भरता के साथ परीक्षण सूट का विस्तार, पुनर्गठन और रखरखाव मुश्किल है।

परीक्षण मामले पर निर्भरता की आवश्यकता के आसपास काम करने के लिए अक्सर पर्याप्त साधन होते हैं। आमतौर पर, यह समस्या सिस्टम अंडर टेस्ट (SUT) की स्थिति से संबंधित है। एक परीक्षण मामले की कार्रवाई प्रणाली की स्थिति को बदल सकती है। कुछ अन्य परीक्षण मामले को ठीक से चलाने के लिए, इस नए राज्य को ज्ञात होना चाहिए।

परीक्षण मामलों के बीच डेटा पास करने के बजाय, यह सिफारिश की जाती है कि परीक्षण मामले राज्य को SUT से पढ़ते हैं और अभिकथन करते हैं (अर्थात, परीक्षण मामले को चलाने दें यदि राज्य अपेक्षित है, अन्यथा रीसेट या विफल)। परीक्षण मामले को ठीक से निष्पादित करने के लिए आवश्यक चर सेट करने के लिए राज्य का उपयोग करने की भी सिफारिश की जाती है। सामान्य क्रियाएं अक्सर आवश्यक मामलों में SUT सेट करने के लिए कॉल मामलों के लिए लाइब्रेरी फ़ंक्शंस के रूप में कार्यान्वित की जा सकती हैं। (इस तरह के सामान्य कार्यों को भी अलग से परीक्षण किया जा सकता है, यदि आवश्यक हो, तो यह सुनिश्चित करने के लिए कि वे अपेक्षित रूप से काम करते हैं)। यह कभी-कभी संभव भी होता है, लेकिन हमेशा एक परीक्षण के मामले में एक साथ समूह परीक्षण के लिए वांछनीय नहीं है, अर्थात्, एक परीक्षण मामले को "परिदृश्य" परीक्षण (उपप्रकारों से युक्त एक परीक्षण) करने दें।

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

  • सर्वर शुरू करना
  • सर्वर को कॉन्फ़िगर करना
  • क्लाइंट को सर्वर से जोड़ना
  • सर्वर से क्लाइंट को डिस्कनेक्ट कर रहा है
  • सर्वर को रोकना

सूचीबद्ध कार्यों के बीच स्पष्ट निर्भरताएं हैं। सर्वर को कॉन्फ़िगर नहीं किया जा सकता है यदि यह पहली बार शुरू नहीं हुआ है, तो क्लाइंट कॉनॉट कनेक्टेड हो सकता है जब तक कि सर्वर ठीक से कॉन्फ़िगर नहीं किया जाता है, और इसी तरह। यदि हम प्रत्येक फ़ंक्शन के लिए एक परीक्षण केस रखना चाहते हैं, तो हमें बताए गए क्रम में परीक्षण मामलों को हमेशा चलाने और डेटा (पहचान, संभालती है, और इसी तरह) को ले जाने की कोशिश की जा सकती है और इसलिए उनके बीच निर्भरता का परिचय दें। ।

इससे बचने के लिए, हम प्रत्येक परीक्षण के लिए सर्वर को शुरू करने और रोकने पर विचार कर सकते हैं। इस प्रकार हम स्टार्ट और स्टॉप एक्शन को लागू कर सकते हैं क्योंकि आम कार्यों को init_per_testcase और end_per_testcase से init_per_testcase किया जा सकता है। (याद रखें कि परीक्षण की शुरुआत और कार्यक्षमता को अलग-अलग रोकना।) कॉन्फ़िगरेशन को एक सामान्य फ़ंक्शन के रूप में भी लागू किया जा सकता है, शायद प्रारंभ फ़ंक्शन के साथ समूहीकृत। अंत में, एक ग्राहक को जोड़ने और डिस्कनेक्ट करने के परीक्षण को एक परीक्षण मामले में बांटा जा सकता है। परिणामी सूट निम्नानुसार लग सकता है:

     
-module(my_server_SUITE).
-compile(export_all).
-include_lib("ct.hrl").

%%% init and end functions...

suite() -> [{require,my_server_cfg}].

init_per_testcase(start_and_stop, Config) ->
    Config;

init_per_testcase(config, Config) ->
    [{server_pid,start_server()} | Config];

init_per_testcase(_, Config) ->
    ServerPid = start_server(),
    configure_server(),
    [{server_pid,ServerPid} | Config].

end_per_testcase(start_and_stop, _) ->
    ok;

end_per_testcase(_, _) ->
    ServerPid = ?config(server_pid),
    stop_server(ServerPid).

%%% test cases...

all() -> [start_and_stop, config, connect_and_disconnect].

%% test that starting and stopping works
start_and_stop(_) ->
    ServerPid = start_server(),
    stop_server(ServerPid).

%% configuration test
config(Config) ->
    ServerPid = ?config(server_pid, Config),
    configure_server(ServerPid).

%% test connecting and disconnecting client
connect_and_disconnect(Config) ->
    ServerPid = ?config(server_pid, Config),
    {ok,SessionId} = my_server:connect(ServerPid),
    ok = my_server:disconnect(ServerPid, SessionId).

%%% common functions...

start_server() ->
    {ok,ServerPid} = my_server:start(),
    ServerPid.

stop_server(ServerPid) ->
    ok = my_server:stop(),
    ok.

configure_server(ServerPid) ->
    ServerCfgData = ct:get_config(my_server_cfg),
    ok = my_server:configure(ServerPid, ServerCfgData),
    ok.

13.2 कॉन्फ़िगरेशन डेटा सहेजना

कभी-कभी यह असंभव है, या स्वतंत्र परीक्षण मामलों को लागू करने के लिए असंभव है। शायद SUT अवस्था को पढ़ना संभव नहीं है। शायद SUT को रीसेट करना असंभव है और सिस्टम को पुनरारंभ करने में बहुत लंबा समय लगता है। उन परिस्थितियों में जहां परीक्षण मामले की निर्भरता आवश्यक है, सीटी एक परीक्षण मामले से अगले तक डेटा ले जाने के लिए एक संरचित तरीका प्रदान करता है। एक टेस्ट सूट से दूसरे में डेटा ले जाने के लिए समान तंत्र का भी उपयोग किया जा सकता है।

डेटा पास करने के तंत्र को save_config कहा जाता है। विचार यह है कि एक परीक्षण मामला (या सूट) Config के मौजूदा मूल्य, या कुंजी-मूल्य ट्यूपल्स की किसी भी सूची को बचा सकता है, ताकि अगला निष्पादन परीक्षण मामला (या परीक्षण सूट) इसे पढ़ सके। कॉन्फ़िगरेशन डेटा स्थायी रूप से सहेजा नहीं गया है, लेकिन केवल एक मामले (या सूट) से अगले में पारित किया जा सकता है।

Config डेटा को बचाने के लिए, tuple {save_config,ConfigList} को end_per_testcase या मुख्य परीक्षण केस फ़ंक्शन से end_per_testcase

पिछले परीक्षण मामले द्वारा सहेजे गए डेटा को पढ़ने के लिए, इस प्रकार एक saved_config कुंजी के साथ मैक्रो config उपयोग करें:

{Saver,ConfigList} = ?config(saved_config, Config)

Saver ( atom() ) पिछले परीक्षण मामले (जहां डेटा सहेजा गया था) का नाम है। config मैक्रो का उपयोग किसी विशेष डेटा को वापस ConfigList लिए भी किया जा सकता है। यह दृढ़ता से अनुशंसा की जाती है कि Saver को हमेशा सहेजे गए परीक्षण मामले के अपेक्षित नाम से मिलान किया जाए। इस तरह, परीक्षण सूट के पुनर्गठन के कारण होने वाली समस्याओं से बचा जा सकता है। इसके अलावा, यह निर्भरता को और अधिक स्पष्ट और परीक्षण सूट को पढ़ने और बनाए रखने में आसान बनाता है।

एक परीक्षण सूट से दूसरे में डेटा पारित करने के लिए, एक ही तंत्र का उपयोग किया जाता है। डेटा को end_per_suite द्वारा सेव किया end_per_suite और सूट में फंक्शन init_per_suite द्वारा पढ़ना है। सुइट्स के बीच डेटा पास करते समय, Saver टेस्ट सूट का नाम रखता है।

उदाहरण:

-module(server_b_SUITE).
-compile(export_all).
-include_lib("ct.hrl").

%%% init and end functions...

init_per_suite(Config) ->
    %% read config saved by previous test suite
    {server_a_SUITE,OldConfig} = ?config(saved_config, Config),
    %% extract server identity (comes from server_a_SUITE)
    ServerId = ?config(server_id, OldConfig),
    SessionId = connect_to_server(ServerId),
    [{ids,{ServerId,SessionId}} | Config].

end_per_suite(Config) ->
    %% save config for server_c_SUITE (session_id and server_id)
    {save_config,Config}

%%% test cases...

all() -> [allocate, deallocate].

allocate(Config) ->
    {ServerId,SessionId} = ?config(ids, Config),
    {ok,Handle} = allocate_resource(ServerId, SessionId),
    %% save handle for deallocation test
    NewConfig = [{handle,Handle}],
    {save_config,NewConfig}.

deallocate(Config) ->
    {ServerId,SessionId} = ?config(ids, Config),
    {allocate,OldConfig} = ?config(saved_config, Config),
    Handle = ?config(handle, OldConfig),
    ok = deallocate_resource(ServerId, SessionId, Handle).

Config किए गए डेटा को एक ऐसे परीक्षण मामले से बचाने के लिए, जिसे छोड़ दिया जाना है, tuple {skip_and_save,Reason,ConfigList}

इसका परिणाम यह होता है कि परीक्षण के मामले को लॉग फ़ाइल में मुद्रित Reason साथ छोड़ दिया जाता है (जैसा कि पहले बताया गया है) और ConfigList को अगले परीक्षण मामले के लिए सहेजा जाता है। ConfigList का उपयोग करके पढ़ा जा सकता है ?config(saved_config, Config) , जैसा कि पहले वर्णित है। skip_and_save को skip_and_save भी लौटाया जा सकता है। इस मामले में, बचाया डेटा init_per_suite द्वारा पढ़ा जा सकता है जो सूट में है।

13.3 अनुक्रम

कभी-कभी परीक्षण के मामले एक-दूसरे पर निर्भर होते हैं ताकि यदि कोई मामला विफल हो जाए, तो निम्नलिखित परीक्षणों को निष्पादित नहीं किया जाना है। आमतौर पर, अगर save_config सुविधा का उपयोग किया जाता है और एक परीक्षण मामला जिसमें डेटा क्रैश को बचाने की उम्मीद की जाती है, तो निम्न मामला नहीं चल सकता है। Common Test ऐसी निर्भरताओं को घोषित करने का एक तरीका प्रदान करता है, जिसे सीक्वेंस कहा जाता है।

अनुक्रम मामलों के साथ परीक्षण मामलों के अनुक्रम को परीक्षण केस समूह के रूप में परिभाषित किया गया है। परीक्षण सूट में टेस्ट केस समूहों को फ़ंक्शन groups/0 माध्यम से परिभाषित किया जाता है (विवरण के लिए, अनुभाग Test Case Groups

उदाहरण के लिए, यह सुनिश्चित करने के लिए कि यदि server_b_SUITE क्रैश में allocate server_b_SUITE है, तो server_b_SUITE को छोड़ दिया जाता है, निम्नलिखित अनुक्रम को परिभाषित किया जा सकता है:

groups() -> [{alloc_and_dealloc, [sequence], [alloc,dealloc]}].

मान लें कि सूट में परीक्षण केस get_resource_status जो अन्य दो मामलों से स्वतंत्र है, तो फ़ंक्शन all इस प्रकार देख सकते हैं:

all() -> [{group,alloc_and_dealloc}, get_resource_status].

यदि alloc सफल होता है, तो dealloc को भी निष्पादित किया जाता है। यदि alloc विफल रहता है, तो SKIPPED निष्पादित नहीं किया जाता है, लेकिन HTML लॉग में SKIPPED के रूप में चिह्नित है। get_resource_status से कोई फर्क नहीं पड़ता है कि alloc_and_dealloc मामलों में क्या होता है।

एक अनुक्रम में परीक्षण मामलों को तब तक निष्पादित किया जाता है जब तक कि सभी सफल या असफल नहीं हो जाते। यदि कोई विफल रहता है, तो अनुक्रम में सभी निम्न मामले छोड़ दिए जाते हैं। अनुक्रम में जो मामले उस बिंदु तक सफल हुए हैं, वे लॉग में सफल बताए जाते हैं। किसी भी क्रम को निर्दिष्ट किया जा सकता है।

उदाहरण:

 groups() -> [{scenarioA, [sequence], [testA1, testA2]}, 
              {scenarioB, [sequence], [testB1, testB2, testB3]}].

 all() -> [test1, 
           test2, 
           {group,scenarioA}, 
test3, 
           {group,scenarioB}, 
           test4].

एक अनुक्रम समूह में उपसमूह हो सकते हैं। ऐसे उपसमूह के पास कोई भी संपत्ति हो सकती है, अर्थात, उन्हें अनुक्रम भी होना आवश्यक नहीं है। यदि आप उपसमूह की स्थिति को ऊपर के स्तर पर अनुक्रम को प्रभावित करना चाहते हैं {return_group_result,Status} end_per_group/2 से {return_group_result,Status} end_per_group/2 , जैसा कि लिखित परीक्षा सूट में अनुभाग Repeated Groups में वर्णित है। एक असफल उपसमूह ( Status == failed ) उसी तरह से अनुक्रम का निष्पादन विफल हो जाता है जिस तरह से एक परीक्षण मामला करता है।