आपको यूनिट परीक्षणों के साथ क्या परीक्षण करना चाहिए?


122

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

समस्या यह है, मुझे नहीं पता कि क्या परीक्षण करना है। क्या मुझे सामान्य मामले का परीक्षण करना चाहिए? किनारे का मामला? मुझे कैसे पता चलेगा कि एक फ़ंक्शन पर्याप्त रूप से कवर किया गया है?

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


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

9
मुझे आश्चर्य है कि लगभग 5 वर्षों के बाद आप इसके बारे में क्या सोचते हैं? क्योंकि अधिक से अधिक मुझे लगता है कि लोगों को आजकल "यूनिट-टेस्ट नहीं करना है" बेहतर पता होना चाहिए। व्यवहार संचालित विकास आपके द्वारा पूछे गए प्रश्नों से विकसित हुआ है।
रेमिजिअस पांकेविसियस

जवाबों:


121

मेरा व्यक्तिगत दर्शन इस प्रकार है:

  1. सब कुछ आप कर सकते हैं के सामान्य मामले का परीक्षण करें। यह आपको बताएगा कि जब आप कुछ बदलाव करते हैं (जो कि मेरी राय में, स्वचालित इकाई परीक्षण का एकमात्र सबसे बड़ा लाभ है) तब यह कोड टूट जाता है।
  2. कुछ असामान्य रूप से जटिल कोड के किनारे के मामलों का परीक्षण करें जो आपको लगता है कि शायद त्रुटियां होंगी।
  3. जब भी आपको कोई बग मिले, उसे ठीक करने से पहले उसे कवर करने के लिए एक टेस्ट केस लिखें
  4. जब भी किसी को मारने का समय हो, कम महत्वपूर्ण कोड में किनारे-केस परीक्षण जोड़ें।

1
इसके लिए धन्यवाद, मैं ओपी के समान सवालों के साथ यहां से गुजर रहा था।
स्टीफन

5
+1, हालाँकि मैं किसी तार्किक लायब्रेरी को सुनिश्चित करने के लिए किसी भी पुस्तकालय / उपयोगिता-प्रकार के कार्यों के किनारे के मामलों का भी परीक्षण करूंगा। उदाहरण के लिए जब एक अशक्त पारित हो जाता है तो क्या होता है? खाली इनपुट के बारे में क्या? यह सुनिश्चित करने में मदद करेगा कि आपका डिज़ाइन तार्किक है और कोने के मामले के व्यवहार का दस्तावेजीकरण करेगा।
मिकेरा

7
# 3 एक बहुत ठोस जवाब की तरह लगता है क्योंकि यह एक वास्तविक जीवन का उदाहरण है कि एक इकाई परीक्षण कैसे मदद कर सकता था। अगर यह एक बार टूट गया तो फिर से टूट सकता है।
रयान ग्रिफिथ

बस शुरू होने के बाद, मुझे लगता है कि मैं परीक्षण के साथ बहुत रचनात्मक नहीं हूं। इसलिए मैं उन्हें ऊपर # 3 के रूप में उपयोग करता हूं, जो मन की शांति सुनिश्चित करता है कि उन कीड़े फिर से कभी नहीं चलेंगे।
अंकुश

आपका उत्तर इस लोकप्रिय मध्यम लेख में दिखाया गया था: hackernoon.com/…
BugHunterUK

67

इस प्रकार उत्तरों के ढेरों के बीच किसी ने भी हाथ में सवाल के जवाब में महत्वपूर्ण विभाजन और सीमा मूल्य विश्लेषण , महत्वपूर्ण विचारों को नहीं छुआ है । अन्य सभी उत्तर, जबकि उपयोगी, गुणात्मक हैं, लेकिन यह संभव है - और बेहतर - यहां मात्रात्मक होना। @fishtoaster कुछ ठोस दिशा निर्देश प्रदान करता है, बस परीक्षण परिमाण के कवर के तहत झांकता है, लेकिन तुल्यता विभाजन और सीमा मूल्य विश्लेषण हमें बेहतर करने की अनुमति देता है।

में तुल्यता विभाजन , आप अपेक्षित परिणाम के आधार पर समूहों में सभी संभव आदानों के सेट विभाजित करते हैं। एक समूह के किसी भी इनपुट से समकक्ष परिणाम मिलेंगे, इस प्रकार ऐसे समूहों को समतुल्य कक्षाएं कहा जाता है । (ध्यान दें कि समान परिणाम का मतलब समान परिणाम नहीं है।)

एक साधारण उदाहरण के रूप में एक प्रोग्राम पर विचार करें जो कि लोअरकेस ASCII वर्णों को अपरकेस वर्णों में बदलना चाहिए। अन्य पात्रों को पहचान परिवर्तन से गुजरना चाहिए, अर्थात अपरिवर्तित रहना चाहिए। यहाँ तुल्यता वर्गों में एक संभावित टूट है:

| # |  Equivalence class    | Input        | Output       | # test cases |
+------------------------------------------------------------------------+
| 1 | Lowercase letter      | a - z        | A - Z        | 26           |
| 2 | Uppercase letter      | A - Z        | A - Z        | 26           |
| 3 | Non-alphabetic chars  | 0-9!@#,/"... | 0-9!@#,/"... | 42           |
| 4 | Non-printable chars   | ^C,^S,TAB... | ^C,^S,TAB... | 34           |

यदि आप उन सभी की गणना करते हैं, तो अंतिम कॉलम परीक्षण मामलों की संख्या की रिपोर्ट करता है। तकनीकी रूप से, @ फिशटोस्टर के नियम 1 के अनुसार, आप 52 परीक्षण मामलों को शामिल करेंगे - जो ऊपर दी गई पहली दो पंक्तियों के लिए "सामान्य मामले" के अंतर्गत आते हैं। @ फिशटोस्टर का नियम 2 पंक्तियों 3 और 4 से कुछ या सभी को जोड़ देगा। लेकिन समतुल्यता विभाजन के साथ प्रत्येक समकक्ष वर्ग में किसी एक परीक्षण मामले का परीक्षण पर्याप्त है। यदि आप "a" या "g" या "w" चुनते हैं तो आप समान कोड पथ का परीक्षण कर रहे हैं। इस प्रकार, आपके पास 52 + के बजाय कुल 4 परीक्षण मामले हैं।

सीमा मूल्य विश्लेषण एक मामूली शोधन की सिफारिश करता है: अनिवार्य रूप से यह बताता है कि एक समतुल्य वर्ग का प्रत्येक सदस्य, अच्छी तरह से, समतुल्य नहीं है। यही है, सीमाओं पर मूल्यों को भी अपने आप में एक परीक्षण मामले के योग्य माना जाना चाहिए। (इसके लिए एक आसान औचित्य कुख्यात ऑफ-बाय-वन त्रुटि है !) इस प्रकार, प्रत्येक तुल्यता वर्ग के लिए आपके पास दो इनपुट हो सकते हैं। उपरोक्त इनपुट डोमेन को देखते हुए - और ASCII मूल्यों के कुछ ज्ञान के साथ - मैं इन परीक्षण मामलों के इनपुट के साथ आ सकता हूं:

| # | Input                | # test cases |
| 1 | a, w, z              | 3            |
| 2 | A, E, Z              | 3            |
| 3 | 0, 5, 9, !, @, *, ~  | 7            |
| 4 | nul, esc, space, del | 4            |

(जैसे ही आपको 3 से अधिक सीमा मूल्य मिलते हैं, जो सुझाव देते हैं कि आप अपने मूल समतुल्य श्रेणी के पुनर्विचारों को पुनर्विचार करना चाह सकते हैं, लेकिन यह काफी सरल था कि मैं उन्हें संशोधित करने के लिए वापस नहीं गया।) इस प्रकार, सीमा मूल्य विश्लेषण हमें सिर्फ ऊपर लाता है। 17 परीक्षण मामले - संपूर्ण कवरेज के उच्च आत्मविश्वास के साथ - संपूर्ण परीक्षण करने के लिए 128 परीक्षण मामलों की तुलना में। (इस बात का उल्लेख नहीं है कि कॉम्बिनेटरिक्स यह सुनिश्चित करते हैं कि संपूर्ण परीक्षण किसी भी वास्तविक दुनिया के अनुप्रयोग के लिए बस संभव है!)


3
+1 यह ठीक है कि मैं सहजता से अपने परीक्षण कैसे लिखूं। अब मैं इस पर एक नाम रख सकता हूं :) यह साझा करने के लिए धन्यवाद।
guillaume31

+1 के लिए "गुणात्मक उत्तर उपयोगी होते हैं, लेकिन यह संभव है - और बेहतर - मात्रात्मक होने के लिए"
जिमी ब्रेक-मैके

मुझे लगता है कि यह एक अच्छा जवाब है अगर निर्देश "मैं अपने परीक्षणों के साथ अच्छा कवरेज कैसे प्राप्त कर सकता हूं"। मुझे लगता है कि इसके शीर्ष पर एक व्यावहारिक दृष्टिकोण खोजने के लिए उपयोगी होगा - क्या यह लक्ष्य है कि हर परत में तर्क के हर टुकड़े की प्रत्येक शाखा को इस तरह से अच्छी तरह से परीक्षण किया जाना चाहिए?
किरेन जॉनस्टोन

18

संभवतः मेरी राय बहुत लोकप्रिय नहीं है। लेकिन मेरा सुझाव है कि आप इकाई परीक्षणों के साथ किफायती रहें। यदि आपके पास बहुत अधिक यूनिट परीक्षण हैं, तो आप वास्तविक कोडिंग के बजाय परीक्षण को बनाए रखने के साथ अपना आधा या अधिक समय आसानी से खर्च कर सकते हैं।

मैं आपको उन चीजों के लिए परीक्षण लिखने का सुझाव देता हूं, जो आपके आंत में खराब भावना या ऐसी चीजें हैं जो बहुत महत्वपूर्ण हैं और / या प्राथमिक हैं। IMHO इकाई परीक्षण अच्छी इंजीनियरिंग और रक्षात्मक कोडिंग के लिए एक प्रतिस्थापन नहीं हैं। वर्तमान में मैं एक ऐसी परियोजना पर काम कर रहा हूं जो कम या ज्यादा बेकार है। यह वास्तव में स्थिर है लेकिन रिफ्लेक्टर के लिए एक दर्द है। वास्तव में किसी ने एक वर्ष में इस कोड को नहीं छुआ है और यह जिस सॉफ्टवेयर स्टैक पर आधारित है वह 4 साल पुराना है। क्यों? क्योंकि यह सटीक होने के लिए, यूनिट परीक्षणों के साथ बरबाद है: यूनिट परीक्षण और स्वचालित एकीकरण परीक्षण। (कभी ककड़ी और इस तरह के बारे में सुना?) और यहाँ सबसे अच्छा हिस्सा है: यह (अभी तक) सॉफ्टवेयर का बेकार टुकड़ा एक कंपनी द्वारा विकसित किया गया है, जिसके कर्मचारी परीक्षण-संचालित विकास के दृश्य में अग्रणी हैं। : डी

तो मेरा सुझाव है:

  • बुनियादी कंकाल विकसित करने के बाद परीक्षण लिखना शुरू करें , अन्यथा रिफैक्टिंग दर्दनाक हो सकता है। एक डेवलपर के रूप में, जो दूसरों के लिए विकसित होता है, आपको शुरू में आवश्यकताओं की आवश्यकता नहीं होती है।

  • सुनिश्चित करें कि आपकी इकाई परीक्षण जल्दी से किया जा सकता है। यदि आपके पास एकीकरण परीक्षण (जैसे ककड़ी) है तो ठीक है यदि वे थोड़ा अधिक समय लेते हैं। लेकिन लंबे समय तक चलने वाले परीक्षण मज़ेदार नहीं हैं, मेरा विश्वास करो। (लोग सभी कारणों को भूल जाते हैं कि C ++ कम लोकप्रिय क्यों हो गया है ...)

  • इस TDD सामान को TDD- विशेषज्ञों के पास छोड़ दें।

  • और हाँ, कभी-कभी आप किनारे के मामलों पर ध्यान केंद्रित करते हैं, कभी-कभी सामान्य मामलों पर, जहां आप अप्रत्याशित की उम्मीद करते हैं। यद्यपि यदि आप हमेशा अप्रत्याशित की उम्मीद करते हैं, तो आपको वास्तव में आपको वर्कफ़्लो और अनुशासन पर पुनर्विचार करना चाहिए। ;-)


2
क्या आप इस बात का अधिक विवरण दे सकते हैं कि परीक्षण इस सॉफ़्टवेयर को रिफलेक्टर के लिए दर्द क्यों बनाते हैं?
माइक पार्टरिज

6
बड़ा +1। इकाई परीक्षणों की दीवारें जो नियमों के बजाय कार्यान्वयन का परीक्षण करती हैं, किसी भी बदलाव के लिए 2-3x की आवश्यकता होती है
TheLQ

9
खराब लिखित उत्पादन कोड की तरह, खराब लिखित इकाई परीक्षण को बनाए रखना मुश्किल है। "बहुत सारे यूनिट परीक्षण" DRY रहने में विफलता की तरह लगते हैं; प्रत्येक परीक्षण को सिस्टम के एक विशिष्ट भाग से निपटना / सिद्ध करना चाहिए।
एलन

1
प्रत्येक इकाई परीक्षण को एक चीज की जांच करनी चाहिए, इसलिए बहुत अधिक इकाई परीक्षण नहीं हैं, लेकिन लापता परीक्षण। यदि आपकी इकाई परीक्षण जटिल हैं, तो यह एक और मुद्दा है।
13:14 पर भयावह

1
-1: मुझे लगता है कि यह पोस्ट खराब लिखी गई है। उल्लेखित कई चीजें हैं, और मुझे नहीं पता कि वे सभी कैसे संबंधित हैं। यदि उत्तर का बिंदु "किफायती" है, तो आपका उदाहरण बिल्कुल कैसे संबंधित है? ऐसा लगता है कि आपकी उदाहरण स्थिति (हालांकि वास्तविक) में खराब यूनिट परीक्षण हैं। कृपया बताएं कि मुझे इससे क्या सबक सीखने हैं और यह मुझे कैसे आर्थिक मदद करता है। इसके अलावा, मैं ईमानदारी से, बस यह नहीं जानता कि आपके कहने का क्या मतलब है Leave this TDD stuff to the TDD-experts
अलेक्जेंडर बर्ड

8

यदि आप पहले टेस्ट ड्रिवेन डेवलपमेंट के साथ परीक्षण कर रहे हैं, तो आपका कवरेज 90% सीमा या उससे अधिक होने वाला है, क्योंकि आप इसके लिए पहली बार एक फेलिंग यूनिट टेस्ट लिखे बिना कार्यक्षमता नहीं जोड़ेंगे।

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


आप उस कवरेज प्रतिशत की गणना कैसे करते हैं? आपके कोड का 90% किसी भी तरह से कवर करने का क्या मतलब है?
zneak

2
@zneak: कोड कवरेज टूल हैं जो आपके लिए उनकी गणना करेंगे। "कोड कवरेज" के लिए एक त्वरित Google को उनमें से कई को लाना चाहिए। उपकरण कोड की उन पंक्तियों को ट्रैक करता है जो परीक्षण चलाते समय निष्पादित की जाती हैं, और आधार जो विधानसभा (ies) में कोड की कुल पंक्तियों को कवरेज प्रतिशत के साथ आने के लिए सहमत करते हैं।
स्टीवन एवर्स

-1। सवाल का जवाब नहीं:The problem is, I don't know _what_ to test
अलेक्जेंडर बर्ड

6

यदि आप टेस्ट ड्रिवेन डेवलपमेंट प्रथाओं का पालन ​​करना शुरू करते हैं, तो वे आपको इस प्रक्रिया के माध्यम से मार्गदर्शन देंगे और यह जानना कि परीक्षण स्वाभाविक रूप से क्या होगा। शुरू करने के लिए कुछ स्थान:

टेस्ट पहले आते हैं

परीक्षण लिखने से पहले कभी भी, कभी भी कोड न लिखें। स्पष्टीकरण के लिए Red-Green-Refactor-दोहराएँ देखें ।

प्रतिगमन परीक्षण लिखें

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

लाल-हरे-Refactor-दोहराएँ

लाल : जिस व्यवहार को आप लागू करने का प्रयास कर रहे हैं, उसके लिए सबसे बुनियादी परीक्षण लिखकर शुरू करें। इस चरण के बारे में कुछ उदाहरण कोड लिखने के बारे में सोचें जो उस वर्ग या फ़ंक्शन का उपयोग करता है जिसे आप काम कर रहे हैं। सुनिश्चित करें कि इसका संकलन है / इसमें कोई सिंटैक्स त्रुटि नहीं है और यह विफल है । यह स्पष्ट होना चाहिए: आपने कोई कोड नहीं लिखा है, इसलिए इसे विफल होना चाहिए, है ना? यहां सीखने के लिए महत्वपूर्ण बात यह है कि जब तक आप परीक्षा को कम से कम एक बार असफल नहीं होते, तब तक आप कभी भी यह सुनिश्चित नहीं कर सकते हैं कि यदि यह पास हो जाता है, तो यह ऐसा करता है क्योंकि आपने कुछ फर्जी कारण से ऐसा किया है।

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

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

दोहराएं : आपको वह किनारे वाला मामला याद है जिसका परीक्षण कवर नहीं हुआ था, है ना? तो, अब यह उसका बड़ा क्षण है। एक टेस्टकेस लिखें जो उस स्थिति को कवर करता है, इसे विफल देखें, कुछ कोड लिखें, इसे पास करें, रिफ्लेक्टर देखें।

अपने कोड का परीक्षण करें

आप कुछ विशिष्ट कोड कोड पर काम कर रहे हैं, और यह वही है जो आप परीक्षण करना चाहते हैं। इसका मतलब है कि आपको लाइब्रेरी फ़ंक्शन, मानक लाइब्रेरी या आपके कंपाइलर का परीक्षण नहीं करना चाहिए। इसके अलावा, "दुनिया" के परीक्षण से बचने की कोशिश करें। इसमें शामिल हैं: बाहरी वेब एपीआई को कॉल करना, कुछ डेटाबेस सघन सामान, आदि। जब भी आप इसे नकली बनाने की कोशिश कर सकते हैं (एक वस्तु जो एक ही इंटरफ़ेस का अनुसरण करती है, लेकिन स्थिर, पूर्वनिर्धारित डेटा लौटाती है)।


1
मान लें कि मेरे पास पहले से ही एक मौजूदा है और (जहाँ तक मैं देख सकता हूँ) वर्किंग कोड बेस, मैं क्या करूँ?
zneak

यह थोड़ा और अधिक कठिन हो सकता है (कोड कैसे लिखा जाता है इसके आधार पर)। प्रतिगमन परीक्षणों से शुरू करें (वे हमेशा समझ में आते हैं), फिर आप अपने आप को साबित करने के लिए इकाई परीक्षण लिखने की कोशिश कर सकते हैं कि आप समझते हैं कि कोड क्या कर रहा है। काम की मात्रा (प्रतीत होता है) करने से अभिभूत होना आसान है, लेकिन: कुछ परीक्षण हमेशा बिना किसी परीक्षण से बेहतर होते हैं।
रिसजार्ड ज़ोपा

3
-1 मुझे नहीं लगता कि यह इस सवाल का बहुत अच्छा जवाब है । प्रश्न टीडीडी के बारे में नहीं है, यह इकाई परीक्षण लिखते समय क्या परीक्षण करना है, इसके बारे में पूछ रहा है । मुझे लगता है कि वास्तविक प्रश्न का एक अच्छा उत्तर एक गैर-टीडीडी पद्धति पर लागू होना चाहिए।
ब्रायन ओकले

1
यदि आप इसे छूते हैं, तो इसका परीक्षण करें। और क्लीन कोड (रॉबर्ट सी मार्टिन) आपको 3 पार्टी कोड के लिए "लर्निंग टेस्ट" लिखने का सुझाव देता है। इस तरह से आप इसका उपयोग करना सीखते हैं, और आपके द्वारा उपयोग किए जा रहे व्यवहार को बदलने के मामले में आपके पास परीक्षण हैं।
रोजर विलोक

3

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

उसी से शुरू करें। जैसा कि आप अनुभव कर रहे हैं कि परीक्षण के सबसे बुनियादी आप सीखना शुरू कर देंगे कि क्या पर्याप्त है या नहीं, और अपने कोड के अन्य पहलुओं को देखना शुरू करें जिन्हें परीक्षण की आवश्यकता है।


0

स्टॉक उत्तर "सब कुछ का परीक्षण करना है जो संभवतः टूट सकता है"

तोड़ने के लिए बहुत सरल क्या है? डेटा फ़ील्ड, ब्रेन-डेड प्रॉपर्टी एक्सेसर्स और इसी तरह के बॉयलरप्लेट ओवरहेड। कुछ भी संभवतः किसी आवश्यकता के कुछ पहचान योग्य हिस्से को लागू करता है, और परीक्षण किए जाने से लाभ हो सकता है।

बेशक, आपके लाभ - और आपके काम करने के वातावरण के तरीके - भिन्न हो सकते हैं।


ठीक है। तो मुझे किन मामलों का परीक्षण करना चाहिए? "सामान्य" मामला? किनारे का मामला?
zneak

3
अंगूठे का नियम? एक या दो स्वर्ण मार्ग के मध्य में, और सिर्फ अंदर और किसी भी किनारों के बाहर।
जेफरी हेंटिन

@ जेफ्रीहैंटिन एक अलग उत्तर में "सीमा मूल्य विश्लेषण" है।
रोजर विल्क
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.