python - वेब स्क्रैपिंग के लिए टेस्ट प्रेरित विकास(टीडीडी)



unit-testing testing (1)

सारांश

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

tldr; क्या टीडीडी में नेटवर्क कनेक्शन से निपटने के लिए कोई सर्वोत्तम अभ्यास है?

पुनरुत्पादक उदाहरण

AbstractScraper.py

from urllib.request import urlopen
from bs4 import BeautifulSoup


class AbstractScraper:

    def __init__(self, url):
        self.url = url
        self.dataDictionary = None

    def makeDataDictionary(self):
        html = urlopen(self.url)
        text = html.read().decode("utf-8")
        soup = BeautifulSoup(text, "lxml")
        self.dataDictionary = {"html": html, "text": text, "soup": soup}

    def writeSoup(self, path):
        with open(path, "w") as outfile:
            outfile.write(self.dataDictionary["soup"].prettify())

TestAbstractScraper.py

import unittest
from http.client import HTTPResponse
from bs4 import BeautifulSoup
from CrackedScrapeProject.scrape.AbstractScraper import AbstractScraper
from io import StringIO


class TestAbstractScraperMethods(unittest.TestCase):

    def setUp(self):
        self.scraper = AbstractScraper("https://docs.python.org/2/library/unittest.html")
        self.scraper.makeDataDictionary()

    def test_dataDictionaryContents(self):
        self.assertTrue(isinstance(self.scraper.dataDictionary, dict))
        self.assertTrue(isinstance(self.scraper.dataDictionary["html"], HTTPResponse))
        self.assertTrue(isinstance(self.scraper.dataDictionary["text"], str))
        self.assertTrue(isinstance(self.scraper.dataDictionary["soup"], BeautifulSoup))
        self.assertSetEqual(set(self.scraper.dataDictionary.keys()), set(["text", "soup", "html"]))

    def test_writeSoup(self):
        filePath = "C:/users/athompson/desktop/testFile.html"
        self.scraper.writeSoup(filePath)
        self.writtenData = open(filePath, "r").read()
        self.assertEqual(self.writtenData, self.scraper.dataDictionary["soup"].prettify())

if __name__ == '__main__':
    suite = unittest.TestLoader().loadTestsFromTestCase(TestAbstractScraperMethods)
    unittest.TextTestRunner(verbosity=2).run(suite)

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

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

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

दूसरी ओर, यदि आप makeDataDictionary से सभी निर्भरताओं को दूर करते हैं, तो आपको कौन से कीड़े मिलेंगे? संभवत: (फ़ंक्शन की अंतिम पंक्ति में) डेटा डिक्शनरी का निर्माण ही गलत हो सकता है (जैसे, कुंजियों के लिए गलत नाम)। इस प्रकार, मेरे दृष्टिकोण से, यह लाइन makeDataDictionary का एकमात्र हिस्सा है जहां वास्तविक इकाई-परीक्षण समझ में आता है।

नतीजतन, ऐसी परिस्थितियों में मेरी सिफारिश पहले से कोड से शुद्ध तर्क (एल्गोरिदमिक कोड) के साथ कोड को अलग करना है जो कि इंटरैक्शन द्वारा वर्चस्व है। उदाहरण के लिए, एक सहायक विधि _makeDataDictionary(html, text, soup) बनाएं _makeDataDictionary(html, text, soup) जो कुछ भी नहीं करता है, लेकिन {"html": html, "text": text, "soup": soup} लौटाएं। फिर, _makeDataDictionary पर यूनिट-परीक्षण को _makeDataDictionary , परन्तु बनाने के लिए नहीं। इसके विपरीत, एकीकरण परीक्षणों के साथ makeDataDictionary परीक्षण करें।

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

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





web-scraping