2016-04-28 4 views
4

Первоначальная проблема

Я пишу класс 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 объекта. Для более сложных ситуаций это станет уродливым и неуправляемым.

Мой вопрос

Является ли это правильный подход в целом? Я не могу найти похожие примеры в Интернете, поэтому я думаю, что мой подход может быть неправильным на более фундаментальном уровне. Любое понимание было бы весьма благодарным.

+0

@ChrisP благодарит за ваше редактирование. Я не поставил метку «scrapy» в первую очередь, потому что я думал, что этот вопрос связан с модульным тестированием в целом. – cyberbikepunk

+0

Это, безусловно, единичное тестирование в целом, но люди, которые делают много царапин, могут иметь уникальные идеи для скребок для модульных испытаний. – ChrisP

+0

В этом конкретном случае «CrawlSpider» я мог уйти с фальсификацией объекта ответа. Делать это вручную сложно, но может ли это помочь? http://requests-mock.readthedocs.io/en/latest/overview.html. Будет ли это хорошим подходом? – cyberbikepunk

ответ

1

Вы видели Spiders Contracts?

Это позволяет протестировать каждый обратный вызов вашего паука, не требуя большого количества кода. Например:

def parse(self, response): 
    """ This function parses a sample response. Some contracts are mingled 
    with this docstring. 

    @url http://www.amazon.com/s?field-keywords=selfish+gene 
    @returns items 1 16 
    @returns requests 0 0 
    @scrapes Title Author Year Price 
    """ 

Используйте команду check для запуска проверки контракта.

Посмотрите на это answer, если хотите что-то еще больше.

+0

Я думаю, что имеет смысл идти на тесты * реальной жизни (интеграции) вместо модульного тестирования, так как сам веб-сайт может измениться. По сути, тот факт, что ваши работы с модулями не гарантирует, что ваши скребки работают. Спасибо за ваше предложение. – cyberbikepunk

+0

По-прежнему ценность в модульных тестах, хотя, как правило, проверяет надежность, хотя и кодирует.Другой ответ, который вы предоставляете (http://stackoverflow.com/questions/6456304/scrapy-unit-testing/12741030#12741030], показывает, как лучше подделать объект ответа, фактически используя 'scrapy'' Request' и Объекты «Ответ». Хороший совет. – cyberbikepunk

Смежные вопросы