Правильное модульное тестирование проекта, созданного с использованием Scrapy, который должен выполнять множество сетевыPython

Программы на Python
Anonymous
Правильное модульное тестирование проекта, созданного с использованием Scrapy, который должен выполнять множество сетевы

Сообщение Anonymous »

Я создаю проект, чтобы добавить его в еще не существующее портфолио, и меня кое-что смущает. Цель проекта — создать наиболее полную коллекцию произведений искусства (рисунков, картин и, возможно, скульптур), которые можно будет просмотреть в Интернете. Многие музеи публикуют свои изображения и метаданные в высоком разрешении для публичного использования, поэтому я создаю самую базовую версию этого проекта: веб-скребок, который извлекает произведения искусства с веб-сайта музеев Метрополитена. Я дошел до того момента, когда эта программа успешно находит ссылку для скачивания и название каждого произведения искусства на первых трех страницах результатов поиска.
Я, наконец, стиснул зубы и пытаюсь узнать, как работает тестирование. Я прочитал пару глав, посвященных тестированию, в книге «Разработка программного обеспечения в Google», и меня сбивает с толку соотнесение этой информации с моим проектом. Ниже я поделюсь соответствующим кодом, который состоит из класса, который создает экземпляр паука Scrapy, методов для получения данных и теста, который я написал для метода parse() этого класса.

Код: Выделить всё

metQueryScraper.py

class MetSpider(scrapy.Spider):
name = 'metQueryScraper'

params = {
"offset": "0"
}
url = "https://www.metmuseum.org/art/collection/search?showOnly=openAccess&"
start_urls = [url]

async def start(self):
temp_url = self.url + urlencode(self.params)
yield scrapy.Request(url = temp_url, callback = self.parse)

def parse(self, response):
relativeURLs = response.xpath("//figure[contains(@class, 'collection-object')]/div[contains(@class, 'collection-object-module')]/a[contains(@href, '/art/collection/search')]") # this xpath selects the DOM elements that contains the artworks link

# For each artObject, make a scrapy request to metmuseum.com/*artObject.link*
for url in relativeURLs:
artObject = ArtObject(title = url.xpath("@title").get())
temp_url = "https://www.metmuseum.org" + url.xpath("@href").get()
yield scrapy.Request(url = temp_url, callback = self.parseObjectDownloadLink, meta = {"artObject": artObject})

nextPage = response.xpath("//div[contains(@class, 'pagination-controls')]/button[contains(@aria-label, 'Next Page')]/@aria-label").get()

if(nextPage is not None and self.params["offset"] != "80"): # the second part of this conditional statement is to limit (for now) how many pages the spider crawls through
self.params["offset"] = str(int(self.params["offset"]) + 40)
temp_url = self.url + urlencode(self.params)
yield scrapy.Request(url = temp_url, callback = self.parse)

def parseObjectDownloadLink(self, response):
# Grab the image download link
downloadLink = response.xpath("//figure[contains(@itemtype, 'ImageObject')]/img[contains(@fetchpriority, 'high')]")
artObject = response.meta.get("artObject")
artObject["link"] = downloadLink.xpath("@src").get()
yield artObject

Код: Выделить всё

test_metQueryScraper.py

from betamax.fixtures.unittest import BetamaxTestCase
from spiders.metQueryScraper import MetSpider
from scrapy.http import HtmlResponse
import os

class TestmetQueryScraper(BetamaxTestCase):
def test_shouldCreateAFileContainingNamesAndLinksOfArtObjects(self):
# Given : An instance of MetSpider...
spider = MetSpider()
with open("./vcr/cassettes/artwork-recorded-session.json", "rb") as file:
fileContents = file.read()

response = HtmlResponse(url = spider.url + '0', body=fileContents)

# When : A "network request" is made to the given URL...

spider.parse(response=response)

# Should : Create a file containing the names and download links to each art object encountered
fileEmptyOrNot = os.stat("../../../artworkData.jsonl").st_size == 0
self.assertEqual(fileEmptyOrNot, True, "Expected contents to be added to file. File is currently empty" )

Я понимаю, что большинство тестов программы обычно должны быть небольшими и быстрыми, поэтому, чтобы избежать выполнения сетевого запроса каждый раз, когда я запускаю этот тест, я использовал betamax, чтобы сохранить ответ сетевого запроса на соответствующий URL-адрес в файл, который я использую в качестве дублера для фактического сетевого запроса. Я думаю, что это тест среднего размера (согласно упомянутой выше книге), поскольку он не отправляет сетевой запрос, но имеет доступ к файловой системе.
Некоторые вещи, которые я не понимаю или в которых не уверен:
  • Это тест среднего масштаба (интеграционный тест) или узкого масштаба (юнит-тест)? Это тестирование поведения одного метода, поэтому я думаю, что это модульный тест, но тот факт, что он так сильно полагается на встроенные методы Scrapy, заставляет меня думать, что это интеграционный тест.
  • В качестве расширения этого вопроса, поскольку большая часть этого проекта, скорее всего, будет построена на основе Scrapy, и так много созданных методов будут использовать методы Scrapy или какую-либо другую библиотеку или структуру, я даже не знаю, что можно считать модульным тестом. Похоже, что большинство из них будут интеграционными или сквозными тестами. Является ли это признаком того, что мой код плохо структурирован?
  • Поскольку этот проект предназначен для выполнения множества сетевых запросов к нескольким веб-сайтам музеев и сохранения больших объемов данных, является ли использованный мною подход сохранения записанного сетевого запроса в формате JSON и использования его для имитации сетевого запроса хорошим? Или есть лучший способ протестировать эти типы операций с использованием реалистичных имитируемых данных?
  • Я пытался сделать этот тест удобным для сопровождения, сделав его ясным, кратким и сосредоточив внимание на поведении, а не на деталях реализации, и не уверен, что я вообще в правильном направлении.
Я действительно новичок в тестировании, поэтому, если кто-нибудь что-нибудь скажет о том, как тестировать такого рода проекты, вы бы мне помогли. очень растерянный начинающий инженер-программист. Спасибо большое!

Вернуться в «Python»