如何正确测试 Scrapy spider Python 生成器函数?
How do I properly test a Scrapy spider Python generator function?
我有一个 Scrapy XMLFeedSpider
,我正在尝试测试以下 parse_node
函数:
def parse_node(self, response, selector):
date = selector.xpath('pubDate/text()').extract_first()
url = selector.xpath('link/text()').extract_first()
if date < self.cutoff_date: # TEST VALIDITY OF THE DATE
print "Invalid date"
self.log("Article %s before crawler start date" % url)
else:
print "Valid date"
yield scrapy.Request(url, self.parse_post)
我正在尝试测试函数的有效日期和无效日期:
@mock.patch('my_spiders.spiders.myspider.scrapy.Request')
def test_parse_node(self, scrapy_request):
scrapy_request.return_value = mock.MagicMock()
self.spider.log = mock.MagicMock()
mock_response = mock.MagicMock()
mock_selector = mock.MagicMock()
date = self.spider.start_date.strftime("%c")
url = "https://google.com"
mock_selector.xpath.return_value.extract_first = mock.MagicMock(
side_effect=[date, url]
)
parsed_node = self.spider.parse_node(mock_response, mock_selector)
self.assertEqual(tuple(parsed_node)[0], scrapy_request.return_value)
self.spider.log.assert_not_called()
scrapy_request.assert_called_once_with(url, self.spider.parse_post)
@mock.patch('my_spiders.spiders.myspider.scrapy.Request')
def test_parse_node_invalid_date(self, scrapy_request):
scrapy_request.return_value = mock.MagicMock()
self.spider.log = mock.MagicMock()
mock_response = mock.MagicMock()
mock_selector = mock.MagicMock()
date_object = self.spider.start_date - datetime.timedelta(days=1)
date = date_object.strftime("%c")
url = "https://google.com"
mock_selector.xpath.return_value.extract_first = mock.MagicMock(
side_effect=[date, url]
)
parsed_node = self.spider.parse_node(mock_response, mock_selector)
# TODO: figure out why this doesn't work
# self.spider.log.assert_called_once()
scrapy_request.assert_not_called()
第一个测试 test_parse_node
按预期运行。问题出在 test_parse_node_invalid_date
函数上。如果我将调试器放在 parse_node
函数中,它不会被调用。 print
函数也不会被调用。
我怀疑这是 yield
statement/generator 的某种问题,但无法弄清楚发生了什么。为什么第二个测试 运行 没有像我预期的那样通过 parse_node
函数?
一个python生成器函数只是returns一个迭代器。要实际调试该迭代器,我必须通过调用 next()
方法来启动迭代过程:
parsed_node = self.spider.parse_node(mock_response, mock_selector).next()
我还必须确保每个测试都实例化一个新的生成器,因为生成器只能迭代一次。
然后我可以逐步完成并根据需要 debug/complete 我的测试。
我有一个 Scrapy XMLFeedSpider
,我正在尝试测试以下 parse_node
函数:
def parse_node(self, response, selector):
date = selector.xpath('pubDate/text()').extract_first()
url = selector.xpath('link/text()').extract_first()
if date < self.cutoff_date: # TEST VALIDITY OF THE DATE
print "Invalid date"
self.log("Article %s before crawler start date" % url)
else:
print "Valid date"
yield scrapy.Request(url, self.parse_post)
我正在尝试测试函数的有效日期和无效日期:
@mock.patch('my_spiders.spiders.myspider.scrapy.Request')
def test_parse_node(self, scrapy_request):
scrapy_request.return_value = mock.MagicMock()
self.spider.log = mock.MagicMock()
mock_response = mock.MagicMock()
mock_selector = mock.MagicMock()
date = self.spider.start_date.strftime("%c")
url = "https://google.com"
mock_selector.xpath.return_value.extract_first = mock.MagicMock(
side_effect=[date, url]
)
parsed_node = self.spider.parse_node(mock_response, mock_selector)
self.assertEqual(tuple(parsed_node)[0], scrapy_request.return_value)
self.spider.log.assert_not_called()
scrapy_request.assert_called_once_with(url, self.spider.parse_post)
@mock.patch('my_spiders.spiders.myspider.scrapy.Request')
def test_parse_node_invalid_date(self, scrapy_request):
scrapy_request.return_value = mock.MagicMock()
self.spider.log = mock.MagicMock()
mock_response = mock.MagicMock()
mock_selector = mock.MagicMock()
date_object = self.spider.start_date - datetime.timedelta(days=1)
date = date_object.strftime("%c")
url = "https://google.com"
mock_selector.xpath.return_value.extract_first = mock.MagicMock(
side_effect=[date, url]
)
parsed_node = self.spider.parse_node(mock_response, mock_selector)
# TODO: figure out why this doesn't work
# self.spider.log.assert_called_once()
scrapy_request.assert_not_called()
第一个测试 test_parse_node
按预期运行。问题出在 test_parse_node_invalid_date
函数上。如果我将调试器放在 parse_node
函数中,它不会被调用。 print
函数也不会被调用。
我怀疑这是 yield
statement/generator 的某种问题,但无法弄清楚发生了什么。为什么第二个测试 运行 没有像我预期的那样通过 parse_node
函数?
一个python生成器函数只是returns一个迭代器。要实际调试该迭代器,我必须通过调用 next()
方法来启动迭代过程:
parsed_node = self.spider.parse_node(mock_response, mock_selector).next()
我还必须确保每个测试都实例化一个新的生成器,因为生成器只能迭代一次。
然后我可以逐步完成并根据需要 debug/complete 我的测试。