कई क्रमपरिवर्तन के साथ कुछ के लिए टीडीडी कैसे करें?


15

एक AI जैसी प्रणाली बनाते समय, जो कई अलग-अलग रास्तों को बहुत तेज़ी से ले सकता है, या वास्तव में किसी भी एल्गोरिथ्म में जिसमें कई अलग-अलग इनपुट होते हैं, संभावित परिणाम सेट में बड़ी संख्या में क्रमपरिवर्तन हो सकते हैं।

टीडीडी का उपयोग करने के लिए क्या दृष्टिकोण लेना चाहिए, जो एक ऐसी प्रणाली का निर्माण करता है जो परिणामों के कई, कई अलग-अलग क्रमपरिवर्तन करता है?


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

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

@SnOrfus मेरा मतलब है कि यह सबसे सामान्य, अल्पविकसित अर्थ, निर्णय लेने की मशीन है।
निकोल

जवाबों:


7

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

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

class Decider {

  public boolean decide(float input, float risk) {

      float inputRand = Math.random();
      if (inputRand > input) {
         float riskRand = Math.random();
      }
      return false;

  }

}

// The usage:
Decider d = new Decider();
d.decide(0.1337f, 0.1337f);

इस पद्धति का परीक्षण करना बहुत कठिन है और केवल एक चीज जिसे आप वास्तव में इकाई परीक्षणों में सत्यापित कर सकते हैं, वह है इसकी सीमा ... लेकिन इसके लिए सीमा पर पहुंचने के लिए बहुत प्रयास करने की आवश्यकता होती है। इसलिए इसके बजाय, आइए एक इंटरफ़ेस और एक ठोस वर्ग बनाकर यादृच्छिकता वाले हिस्से को हटा दें, जो कार्यक्षमता को लपेटता है:

public interface IRandom {

   public float random();

}

public class ConcreteRandom implements IRandom {

   public float random() {
      return Math.random();
   }

}

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

class Decider {

  IRandom irandom;

  public Decider(IRandom irandom) { // constructor injection
      this.irandom = irandom;
  }

  public boolean decide(float input, float risk) {

      float inputRand = irandom.random();
      if (inputRand > input) {
         float riskRand = irandom.random();
      }
      return false;

  }

}

// The usage:
Decider d = new Decider(new ConcreteRandom);
d.decide(0.1337f, 0.1337f);

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

class MockedRandom() implements IRandom {

    public List<Float> floats = new ArrayList<Float>();
    int pos;

   public void addFloat(float f) {
     floats.add(f);
   }

   public float random() {
      float out = floats.get(pos);
      if (pos != floats.size()) {
         pos++;
      }
      return out;
   }

}

सबसे अच्छी बात यह है कि यह "वास्तविक" ठोस कार्यान्वयन को पूरी तरह से बदल सकता है। इस तरह परीक्षण करना आसान हो जाता है:

@Before void setUp() {
  MockedRandom mRandom = new MockedRandom();

  Decider decider = new Decider(mRandom);
}

@Test
public void testDecisionWithLowInput_ShouldGiveFalse() {

  mRandom.addFloat(0f);

  assertFalse(decider.decide(0.1337f, 0.1337f));
}

@Test
public void testDecisionWithHighInputRandButLowRiskRand_ShouldGiveFalse() {

  mRandom.addFloat(1f);
  mRandom.addFloat(0f);

  assertFalse(decider.decide(0.1337f, 0.1337f));
}

@Test
public void testDecisionWithHighInputRandAndHighRiskRand_ShouldGiveTrue() {

  mRandom.addFloat(1f);
  mRandom.addFloat(1f);

  assertTrue(decider.decide(0.1337f, 0.1337f));
}

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


3

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

इसके लिए कुछ ज्ञान की आवश्यकता होती है कि कार्यान्वयन क्या अच्छा होगा, लेकिन यह एक सैद्धांतिक चिंता का विषय है - आप एक एआई के निर्माण की अत्यधिक संभावना नहीं है जो गैर-तकनीकी उपयोगकर्ताओं द्वारा विस्तार से निर्दिष्ट किया गया था। यह उसी श्रेणी में है जैसे परीक्षण के मामलों में हार्डकॉडिंग द्वारा परीक्षण पास करना - आधिकारिक तौर पर परीक्षण कल्पना है और कार्यान्वयन सही और सबसे तेज़ संभव समाधान दोनों है, लेकिन यह वास्तव में कभी नहीं होता है।


2

टीडीडी परीक्षण के बारे में नहीं है, यह डिजाइन के बारे में है।

जटिलता के साथ गिरने से दूर, यह इन परिस्थितियों में उत्कृष्टता देता है। यह आपको छोटे टुकड़ों में बड़ी समस्या पर विचार करने के लिए प्रेरित करेगा, जिससे एक बेहतर डिजाइन तैयार होगा।

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

संपादित करें: मैं एक उदाहरण जोड़ना चाहता था, लेकिन पहले समय नहीं था।

आइए एक इन-प्लेस-सॉर्ट एल्गोरिथ्म पर विचार करें। हम आगे जा सकते हैं और परीक्षण लिख सकते हैं जो सरणी के ऊपरी छोर, सरणी के निचले छोर और मध्य में सभी प्रकार के अजीब संयोजनों को कवर करते हैं। प्रत्येक के लिए, हमें किसी प्रकार की वस्तु का एक पूरा सरणी बनाना होगा। इसमें समय लगेगा।

या हम चार भागों में समस्या से निपट सकते हैं:

  1. सरणी को पार करें।
  2. चयनित वस्तुओं की तुलना करें।
  3. आइटम स्विच करें।
  4. उपरोक्त तीनों का समन्वय करें।

पहली समस्या का एकमात्र जटिल हिस्सा है लेकिन इसे बाकी हिस्सों से अलग करके, आपने इसे बहुत सरल बना दिया है।

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

तीसरा परीक्षण करने के लिए अविश्वसनीय रूप से आसान है।

चौथा सिर्फ दो पॉइंटर्स को हैंडल करता है, ट्रैवर्सल क्लास को पॉइंटर्स को इधर-उधर करने के लिए कहता है, एक कॉल करता है और उस तुलना के परिणाम के आधार पर, आइटम को स्वैप करने के लिए कॉल करता है। यदि आपने पहली तीन समस्याओं का सामना किया है, तो आप इसे बहुत आसानी से परख सकते हैं।

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

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


1

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

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


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

0

किनारे के मामलों को लें और कुछ यादृच्छिक इनपुट।

छँटाई का उदाहरण लेने के लिए:

  • कुछ यादृच्छिक सूचियों को क्रमबद्ध करें
  • पहले से हल की गई एक सूची लें
  • एक सूची लें जो रिवर्स ऑर्डर में है
  • एक सूची लें जिसे लगभग क्रमबद्ध किया गया है

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

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