diff --git a/scrapy/contracts/__init__.py b/scrapy/contracts/__init__.py index 851a26a8e..ba8450820 100644 --- a/scrapy/contracts/__init__.py +++ b/scrapy/contracts/__init__.py @@ -42,7 +42,11 @@ class ContractsManager(object): requests = [] for method in self.tested_methods_from_spidercls(type(spider)): bound_method = spider.__getattribute__(method) - requests.append(self.from_method(bound_method, results)) + try: + requests.append(self.from_method(bound_method, results)) + except Exception: + case = _create_testcase(bound_method, 'contract') + results.addError(case, sys.exc_info()) return requests diff --git a/tests/test_contracts.py b/tests/test_contracts.py index fc5c94771..cf62581e4 100644 --- a/tests/test_contracts.py +++ b/tests/test_contracts.py @@ -25,6 +25,21 @@ class ResponseMock(object): url = 'http://scrapy.org' +class CustomSuccessContract(Contract): + name = 'custom_success_contract' + + def adjust_request_args(self, args): + args['url'] = 'http://scrapy.org' + return args + + +class CustomFailContract(Contract): + name = 'custom_fail_contract' + + def adjust_request_args(self, args): + raise TypeError('Error in adjust_request_args') + + class CustomFormContract(Contract): name = 'custom_form' request_cls = FormRequest @@ -118,12 +133,39 @@ class TestSpider(Spider): pass +class CustomContractSuccessSpider(Spider): + name = 'custom_contract_success_spider' + + def parse(self, response): + """ + @custom_success_contract + """ + pass + + +class CustomContractFailSpider(Spider): + name = 'custom_contract_fail_spider' + + def parse(self, response): + """ + @custom_fail_contract + """ + pass + + class InheritsTestSpider(TestSpider): name = 'inherits_demo_spider' class ContractsManagerTest(unittest.TestCase): - contracts = [UrlContract, ReturnsContract, ScrapesContract, CustomFormContract] + contracts = [ + UrlContract, + ReturnsContract, + ScrapesContract, + CustomFormContract, + CustomSuccessContract, + CustomFailContract, + ] def setUp(self): self.conman = ContractsManager(self.contracts) @@ -137,6 +179,9 @@ class ContractsManagerTest(unittest.TestCase): self.assertTrue(self.results.failures) self.assertFalse(self.results.errors) + def should_error(self): + self.assertTrue(self.results.errors) + def test_contracts(self): spider = TestSpider() @@ -209,6 +254,13 @@ class ContractsManagerTest(unittest.TestCase): request.callback(response) self.should_fail() + def test_custom_contracts(self): + self.conman.from_spider(CustomContractSuccessSpider(), self.results) + self.should_succeed() + + self.conman.from_spider(CustomContractFailSpider(), self.results) + self.should_error() + def test_errback(self): spider = TestSpider() response = ResponseMock()