Я, наконец, стиснул зубы и пытаюсь узнать, как работает тестирование. Я прочитал пару глав, посвященных тестированию, в книге «Разработка программного обеспечения в 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" )
Некоторые вещи, которые я не понимаю или в которых не уверен:
- Это тест среднего масштаба (интеграционный тест) или узкого масштаба (юнит-тест)? Это тестирование поведения одного метода, поэтому я думаю, что это модульный тест, но тот факт, что он так сильно полагается на встроенные методы Scrapy, заставляет меня думать, что это интеграционный тест.
- В качестве расширения этого вопроса, поскольку большая часть этого проекта, скорее всего, будет построена на основе Scrapy, и так много созданных методов будут использовать методы Scrapy или какую-либо другую библиотеку или структуру, я даже не знаю, что можно считать модульным тестом. Похоже, что большинство из них будут интеграционными или сквозными тестами. Является ли это признаком того, что мой код плохо структурирован?
- Поскольку этот проект предназначен для выполнения множества сетевых запросов к нескольким веб-сайтам музеев и сохранения больших объемов данных, является ли использованный мною подход сохранения записанного сетевого запроса в формате JSON и использования его для имитации сетевого запроса хорошим? Или есть лучший способ протестировать эти типы операций с использованием реалистичных имитируемых данных?
- Я пытался сделать этот тест удобным для сопровождения, сделав его ясным, кратким и сосредоточив внимание на поведении, а не на деталях реализации, и не уверен, что я вообще в правильном направлении.