Erlang 21 - 1. cover

1 कवर




erlang

1 कवर

१.१ परिचय

मॉड्यूल cover एरलांग कार्यक्रमों के कवरेज विश्लेषण के लिए फ़ंक्शन का एक सेट प्रदान करता है, जो यह गिनती करता है कि प्रत्येक executable line को कितनी बार निष्पादित किया जाता है।

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

1.2 कवर के साथ शुरुआत करना

उदाहरण

मान लें कि निम्न प्रोग्राम के लिए एक परीक्षण मामले को सत्यापित किया जाना चाहिए:

-module(channel).
-behaviour(gen_server).

-export([start_link/0,stop/0]).
-export([alloc/0,free/1]). % client interface
-export([init/1,handle_call/3,terminate/2]). % callback functions

start_link() ->
    gen_server:start_link({local,channel},channel,[],[]).

stop() ->
    gen_server:call(channel,stop).

%%%-Client interface functions-------------------------------------------

alloc() ->
    gen_server:call(channel,alloc).

free(Channel) ->
    gen_server:call(channel,{free,Channel}).

%%%-gen_server callback functions----------------------------------------

init(_Arg) ->
    {ok,channels()}.

handle_call(stop,Client,Channels) ->
    {stop,normal,ok,Channels};

handle_call(alloc,Client,Channels) ->
    {Ch,Channels2} = alloc(Channels),
    {reply,{ok,Ch},Channels2};

handle_call({free,Channel},Client,Channels) ->
    Channels2 = free(Channel,Channels),
    {reply,ok,Channels2}.

terminate(_Reason,Channels) ->
    ok.

%%%-Internal functions---------------------------------------------------

channels() ->
    [ch1,ch2,ch3].

alloc([Channel|Channels]) ->
    {Channel,Channels};
alloc([]) ->
    false.

free(Channel,Channels) ->
    [Channel|Channels].

परीक्षण मामले को निम्नानुसार लागू किया गया है:

-module(test).
-export([s/0]).

s() ->
    {ok,Pid} = channel:start_link(),
    {ok,Ch1} = channel:alloc(),
    ok = channel:free(Ch1),
    ok = channel:stop().

तैयारी

सबसे पहले, कवर शुरू किया जाना चाहिए। यह एक प्रक्रिया को कवर करता है जो कवर डेटाबेस का मालिक है जहां सभी कवरेज डेटा संग्रहीत किए जाएंगे।

1> cover:start().
{ok,<0.30.0>}

कवरेज विश्लेषण में अन्य नोड्स को शामिल करने के लिए, start/1 उपयोग करें। सभी कवर संकलित मॉड्यूल तब सभी नोड्स पर लोड किए जाएंगे, और विश्लेषण करते समय सभी नोड्स के डेटा को संक्षेप में प्रस्तुत किया जाएगा। सादगी के लिए इस उदाहरण में केवल वर्तमान नोड शामिल है।

इससे पहले कि कोई विश्लेषण हो सके, इसमें शामिल मॉड्यूल को कवर संकलित किया जाना चाहिए। इसका मतलब यह है कि बाइनरी में संकलित होने से पहले कुछ अतिरिक्त जानकारी मॉड्यूल में जोड़ दी जाती है जो तब loaded । मॉड्यूल की स्रोत फ़ाइल प्रभावित नहीं होती है और कोई .beam फ़ाइल नहीं बनाई जाती है।

2> cover:compile_module(channel).
{ok,channel}

हर बार कवर संकलित मॉड्यूल channel में एक फ़ंक्शन को कॉल किया जाता है, कॉल डेटाबेस के बारे में कॉल के बारे में जानकारी जोड़ी जाएगी। परीक्षण मामला चलाएँ:

3> test:s().
ok

कवर डेटाबेस की सामग्री की जांच करके कवर विश्लेषण किया जाता है। आउटपुट दो मापदंडों, Level और Analysis द्वारा निर्धारित किया जाता है। Analysis या तो coverage या calls और विश्लेषण के प्रकार को निर्धारित करता है। Level या तो module , function , clause या line और विश्लेषण के स्तर को निर्धारित करता है।

कवरेज विश्लेषण

टाइप coverage का विश्लेषण यह पता लगाने के लिए उपयोग किया जाता है कि कोड को कितना निष्पादित किया गया है और कितना निष्पादित नहीं किया गया है। कवरेज का प्रतिनिधित्व एक टपल {Cov,NotCov} , जहां Cov निष्पादन योग्य लाइनों की संख्या है जिन्हें कम से कम एक बार निष्पादित किया गया है और NotCov निष्पादन योग्य लाइनों की संख्या है जिन्हें निष्पादित नहीं किया गया है।

यदि विश्लेषण मॉड्यूल स्तर पर किया जाता है, तो परिणाम पूरे मॉड्यूल के लिए एक टपल {Module,{Cov,NotCov}} :

4> cover:analyse(channel,coverage,module).
{ok,{channel,{14,1}}}

channel , परिणाम दिखाता है कि मॉड्यूल में 14 लाइनें कवर की गई हैं, लेकिन एक लाइन कवर नहीं है।

यदि विश्लेषण फ़ंक्शन स्तर पर किया जाता है, तो परिणाम को {Function,{Cov,NotCov}} की सूची के रूप में दिया जाता है {Function,{Cov,NotCov}} , मॉड्यूल में प्रत्येक फ़ंक्शन के लिए एक। एक फ़ंक्शन इसके मॉड्यूल नाम, फ़ंक्शन नाम और arity द्वारा निर्दिष्ट किया जाता है:

5> cover:analyse(channel,coverage,function).
{ok,[{{channel,start_link,0},{1,0}},
     {{channel,stop,0},{1,0}},
     {{channel,alloc,0},{1,0}},
     {{channel,free,1},{1,0}},
     {{channel,init,1},{1,0}},
     {{channel,handle_call,3},{5,0}},
     {{channel,terminate,2},{1,0}},
     {{channel,channels,0},{1,0}},
     {{channel,alloc,1},{1,1}},
     {{channel,free,2},{1,0}}]}

channel , परिणाम दिखाता है कि खुला channel:alloc/1 फ़ंक्शन channel:alloc/1

यदि विश्लेषण क्लॉज स्तर पर किया जाता है, तो परिणाम को {Clause,{Cov,NotCov}} की सूची के रूप में दिया जाता है {Clause,{Cov,NotCov}} , मॉड्यूल में प्रत्येक फ़ंक्शन क्लॉज के लिए एक। एक क्लॉज इसके मॉड्यूल नाम, फंक्शन नेम, एरिटी और पोजीशन के फंक्शन डेफिनिशन द्वारा निर्दिष्ट किया जाता है:

6> cover:analyse(channel,coverage,clause).
{ok,[{{channel,start_link,0,1},{1,0}},
     {{channel,stop,0,1},{1,0}},
     {{channel,alloc,0,1},{1,0}},
     {{channel,free,1,1},{1,0}},
     {{channel,init,1,1},{1,0}},
     {{channel,handle_call,3,1},{1,0}},
     {{channel,handle_call,3,2},{2,0}},
     {{channel,handle_call,3,3},{2,0}},
     {{channel,terminate,2,1},{1,0}},
     {{channel,channels,0,1},{1,0}},
     {{channel,alloc,1,1},{1,0}},
     {{channel,alloc,1,2},{0,1}},
     {{channel,free,2,1},{1,0}}]}

channel , परिणाम दिखाता है कि खुला लाइन channel:alloc/1 के दूसरे खंड में channel:alloc/1

अंत में, यदि विश्लेषण लाइन स्तर पर किया जाता है, तो परिणाम को ट्यूपल्स {Line,{Cov,NotCov}} सूची के रूप में दिया जाता है, जो स्रोत कोड में प्रत्येक निष्पादन योग्य लाइन के लिए एक है। एक लाइन इसके मॉड्यूल नाम और लाइन नंबर द्वारा निर्दिष्ट की जाती है।

7> cover:analyse(channel,coverage,line).
{ok,[{{channel,9},{1,0}},
     {{channel,12},{1,0}},
     {{channel,17},{1,0}},
     {{channel,20},{1,0}},
     {{channel,25},{1,0}},
     {{channel,28},{1,0}},
     {{channel,31},{1,0}},
     {{channel,32},{1,0}},
     {{channel,35},{1,0}},
     {{channel,36},{1,0}},
     {{channel,39},{1,0}},
     {{channel,44},{1,0}},
     {{channel,47},{1,0}},
     {{channel,49},{0,1}},
     {{channel,52},{1,0}}]}

channel , परिणाम दिखाता है कि खुला लाइन लाइन नंबर 49 है।

सांख्यिकी को बुलाओ

टाइप calls का विश्लेषण यह पता लगाने के लिए किया जाता है कि किसी चीज को कितनी बार calls किया गया है और एक पूर्णांक Calls द्वारा दर्शाया गया है।

यदि विश्लेषण मॉड्यूल स्तर पर किया जाता है, तो परिणाम एक ट्यूल {Module,Calls} रूप में दिया जाता है। यहां Calls मॉड्यूल में फ़ंक्शनों की कुल संख्या है:

8> cover:analyse(channel,calls,module).
{ok,{channel,12}}

channel , परिणाम दिखाता है कि मॉड्यूल में फ़ंक्शन के लिए कुल बारह कॉल किए गए हैं।

यदि विश्लेषण फ़ंक्शन स्तर पर किया जाता है, तो परिणाम ट्यूपल्स की एक सूची के रूप में दिया जाता है {Function,Calls} । यहां Calls प्रत्येक फ़ंक्शन के लिए कॉल की संख्या है:

9> cover:analyse(channel,calls,function).
{ok,[{{channel,start_link,0},1},
     {{channel,stop,0},1},
     {{channel,alloc,0},1},
     {{channel,free,1},1},
     {{channel,init,1},1},
     {{channel,handle_call,3},3},
     {{channel,terminate,2},1},
     {{channel,channels,0},1},
     {{channel,alloc,1},1},
     {{channel,free,2},1}]}

channel , परिणाम दिखाता है कि handle_call/3 मॉड्यूल (तीन कॉल) में सबसे अधिक कहा जाता है। अन्य सभी कार्यों को एक बार बुलाया गया है।

यदि विश्लेषण क्लॉज स्तर पर किया जाता है, तो परिणाम ट्यूपल्स {Clause,Calls} की एक सूची के रूप में दिया जाता है। यहां Calls प्रत्येक फ़ंक्शन क्लॉज के लिए कॉल की संख्या है:

10> cover:analyse(channel,calls,clause).
{ok,[{{channel,start_link,0,1},1},
     {{channel,stop,0,1},1},
     {{channel,alloc,0,1},1},
     {{channel,free,1,1},1},
     {{channel,init,1,1},1},
     {{channel,handle_call,3,1},1},
     {{channel,handle_call,3,2},1},
     {{channel,handle_call,3,3},1},
     {{channel,terminate,2,1},1},
     {{channel,channels,0,1},1},
     {{channel,alloc,1,1},1},
     {{channel,alloc,1,2},0},
     {{channel,free,2,1},1}]}

channel , परिणाम से पता चलता है कि सभी खंडों को एक बार बुलाया गया है, channel:alloc/1 के दूसरे खंड को छोड़कर channel:alloc/1 जिसे बिल्कुल भी नहीं बुलाया गया है।

अंत में, यदि विश्लेषण लाइन स्तर पर किया जाता है, तो परिणाम ट्यूपल्स की एक सूची के रूप में दिया जाता है {Line,Calls} । यहां Calls प्रत्येक पंक्ति को निष्पादित किए जाने की संख्या है:

11> cover:analyse(channel,calls,line).
{ok,[{{channel,9},1},
     {{channel,12},1},
     {{channel,17},1},
     {{channel,20},1},
     {{channel,25},1},
     {{channel,28},1},
     {{channel,31},1},
     {{channel,32},1},
     {{channel,35},1},
     {{channel,36},1},
     {{channel,39},1},
     {{channel,44},1},
     {{channel,47},1},
     {{channel,49},0},
     {{channel,52},1}]}

channel , परिणाम से पता चलता है कि सभी लाइनों को एक बार निष्पादित किया गया है, लाइन नंबर 49 को छोड़कर, जिसे बिल्कुल भी निष्पादित नहीं किया गया है।

फाइल का विश्लेषण

channel का एक लाइन स्तर कॉल विश्लेषण cover:analysis_to_file/1 का उपयोग करके एक फ़ाइल में लिखा जा सकता है cover:analysis_to_file/1 :

12> cover:analyse_to_file(channel).
{ok,"channel.COVER.out"}

फ़ंक्शन Channel.erl की एक प्रति बनाता है जहां यह प्रत्येक निष्पादन योग्य पंक्ति के लिए निर्दिष्ट किया जाता है कि उस पंक्ति को कितनी बार निष्पादित किया गया है। आउटपुट फ़ाइल को channel.COVER.out कहा जाता है।

File generated from channel.erl by COVER 2001-05-21 at 11:16:38

****************************************************************************

        |  -module(channel).
        |  -behaviour(gen_server).
        |  
        |  -export([start_link/0,stop/0]).
        |  -export([alloc/0,free/1]). % client interface
        |  -export([init/1,handle_call/3,terminate/2]). % callback functions
        |  
        |  start_link() ->
     1..|      gen_server:start_link({local,channel},channel,[],[]).
        |  
        |  stop() ->
     1..|      gen_server:call(channel,stop).
        |  
        |  %%%-Client interface functions------------------------------------
        |  
        |  alloc() ->
     1..|      gen_server:call(channel,alloc).
        |  
        |  free(Channel) ->
     1..|      gen_server:call(channel,{free,Channel}).
        |  
        |  %%%-gen_server callback functions---------------------------------
        |  
        |  init(_Arg) ->
     1..|      {ok,channels()}.
        |  
        |  handle_call(stop,Client,Channels) ->
     1..|      {stop,normal,ok,Channels};
        |  
        |  handle_call(alloc,Client,Channels) ->
     1..|      {Ch,Channels2} = alloc(Channels),
     1..|      {reply,{ok,Ch},Channels2};
        |  
        |  handle_call({free,Channel},Client,Channels) ->
     1..|      Channels2 = free(Channel,Channels),
     1..|      {reply,ok,Channels2}.
        |  
        |  terminate(_Reason,Channels) ->
     1..|      ok.
        |  
        |  %%%-Internal functions--------------------------------------------
        |  
        |  channels() ->
     1..|      [ch1,ch2,ch3].
        |  
        |  alloc([Channel|Channels]) ->
     1..|      {Channel,Channels};
        |  alloc([]) ->
     0..|      false.
        |  
        |  free(Channel,Channels) ->
     1..|      [Channel|Channels].

निष्कर्ष

विश्लेषणों से परिणामों को देखकर, यह कटौती की जा सकती है कि परीक्षण का मामला मामले को कवर नहीं करता है जब सभी चैनल आवंटित किए जाते हैं और test.erl किया जाता है। तदनुसार इसे बढ़ाया जाना चाहिए।
संयोग से, जब परीक्षण मामले को channel में बग को ठीक किया जाता है तो वास्तव में खोजा जाना चाहिए।

जब कवर विश्लेषण तैयार हो जाता है, तो कवर बंद कर दिया जाता है और सभी कवर संकलित मॉड्यूल loaded जाते हैं। channel के लिए कोड अब वर्तमान पथ में एक .beam फ़ाइल से हमेशा की तरह लोड किया गया है।

13> code:which(channel).
cover_compiled
14> cover:stop().
ok
15> code:which(channel).
"./channel.beam"

१.३ विविध

प्रदर्शन

कवर संकलित मॉड्यूल में कोड का निष्पादन धीमा है और नियमित रूप से संकलित मॉड्यूल की तुलना में अधिक मेमोरी खपत है। चूंकि कवर डेटाबेस में प्रत्येक कवर संकलित मॉड्यूल में प्रत्येक निष्पादन योग्य रेखा के बारे में जानकारी होती है, इसलिए प्रदर्शन कवर संकलित मॉड्यूल के आकार और संख्या के अनुपात में घट जाता है।

कवर के परिणामों का विश्लेषण करते समय प्रदर्शन में सुधार करने के लिए एक बार में analyse और analyse करने के लिए कई कॉल करना संभव है। आप async_analyse_to_file सुविधा फ़ंक्शन का उपयोग भी कर सकते हैं।

निष्पादन योग्य लाइनें

कवर निष्पादन योग्य रेखाओं की अवधारणा का उपयोग करता है, जो एक निष्पादन या फ़ंक्शन कॉल जैसे निष्पादन योग्य अभिव्यक्ति वाले कोड की लाइनें हैं। एक खाली लाइन या एक लाइन जिसमें एक टिप्पणी, फ़ंक्शन हेड या पैटर्न receive - या receive स्टेटमेंट निष्पादन योग्य नहीं receive है।

नीचे दिए गए उदाहरण में, लाइनें संख्या 2,4,6,8 और 11 निष्पादन योग्य लाइनें हैं:

1: is_loaded(Module,Compiled) ->
2:   case get_file(Module,Compiled) of
3:     {ok,File} ->
4:       case code:which(Module) of
5:         ?TAG ->
6:           {loaded,File};
7:         _ ->
8:           unloaded
9:       end;
10:    false ->
11:      false
12:  end.

कोड लोड हो रहा है तंत्र

जब एक मॉड्यूल कवर संकलित किया जाता है, तो इसे अर्लंग के सामान्य कोड लोडिंग तंत्र का उपयोग करके भी लोड किया जाता है। इसका मतलब यह है कि अगर एक कवर संकलित मॉड्यूल को कवर सत्र के दौरान फिर से लोड किया जाता है, उदाहरण के लिए c(Module) का उपयोग करते हुए, यह अब कवर संकलित नहीं होगा।

cover:is_compiled/1 उपयोग करें cover:is_compiled/1 या code:which/1 यह देखने के लिए कि क्या मॉड्यूल कवर संकलित है (और अभी भी लोड है) या नहीं।

जब कवर बंद कर दिया जाता है, तो सभी कवर संकलित मॉड्यूल अनलोड किए जाते हैं।