Первоначальная проблема
Я пишу класс CrawlSpider (используя scrapy
библиотеку) и полагаться на много scrapy
асинхронной магии, чтобы заставить его работать. Вот она, урезанная:Создать блок-тест для метода Scrapy CrawlSpider
class MySpider(CrawlSpider):
rules = [Rule(LinkExtractor(allow='myregex'), callback='parse_page')]
# some other class attributes
def __init__(self, *args, **kwargs):
super(MySpider, self).__init__(*args, **kwargs)
self.response = None
self.loader = None
def parse_page_section(self):
soup = BeautifulSoup(self.response.body, 'lxml')
# Complicated scraping logic using BeautifulSoup
self.loader.add_value(mykey, myvalue)
# more methods parsing other sections of the page
# also using self.response and self.loader
def parse_page(self, response):
self.response = response
self.loader = ItemLoader(item=Item(), response=response)
self.parse_page_section()
# call other methods to collect more stuff
self.loader.load_item()
Атрибут класса rule
говорит мой паук следовать определенным ссылкам и перейти к функции обратного вызова после того, как веб-страницы загружаются. Моя цель - проверить метод разбора, называемый parse_page_section
, без запуска искателя или даже создания реальных HTTP-запросов.
То, что я пытался
Инстинктивно, обратился я к mock
библиотеке. Я понимаю, как вы издеваетесь над функцией, чтобы проверить, была ли она вызвана (с какими аргументами и были ли какие-либо побочные эффекты ...), но это не то, что я хочу. Я хочу создать экземпляр поддельного объекта MySpider
и присвоить достаточно атрибутов, чтобы иметь возможность называть метод parse_page_section
.
В приведенном выше примере, мне нужен response
объекта для создания экземпляра моего ItemLoader
и, в частности атрибута self.response.body
для создания экземпляра моего BeautifulSoup
. В принципе, я мог бы сделать поддельные предметы, как это:
from argparse import Namespace
my_spider = MySpider(CrawlSpider)
my_spider.response = NameSpace(body='<html>...</html>')
Это хорошо работает, чтобы для BeautifulSoup
класса, но мне нужно добавить дополнительные атрибуты для создания ItemLoader
объекта. Для более сложных ситуаций это станет уродливым и неуправляемым.
Мой вопрос
Является ли это правильный подход в целом? Я не могу найти похожие примеры в Интернете, поэтому я думаю, что мой подход может быть неправильным на более фундаментальном уровне. Любое понимание было бы весьма благодарным.
@ChrisP благодарит за ваше редактирование. Я не поставил метку «scrapy» в первую очередь, потому что я думал, что этот вопрос связан с модульным тестированием в целом. – cyberbikepunk
Это, безусловно, единичное тестирование в целом, но люди, которые делают много царапин, могут иметь уникальные идеи для скребок для модульных испытаний. – ChrisP
В этом конкретном случае «CrawlSpider» я мог уйти с фальсификацией объекта ответа. Делать это вручную сложно, но может ли это помочь? http://requests-mock.readthedocs.io/en/latest/overview.html. Будет ли это хорошим подходом? – cyberbikepunk