1
+ import sys
1
2
import re
2
3
from functools import wraps
4
+ from unittest import TestCase
3
5
4
6
from scrapy .http import Request
5
7
from scrapy .utils .spider import iterate_spider_output
6
8
from scrapy .utils .python import get_spec
7
- from scrapy .exceptions import ContractFail
8
9
9
10
10
11
class ContractsManager (object ):
@@ -27,7 +28,7 @@ def extract_contracts(self, method):
27
28
28
29
return contracts
29
30
30
- def from_method (self , method , fail = False ):
31
+ def from_method (self , method , results ):
31
32
contracts = self .extract_contracts (method )
32
33
if contracts :
33
34
# calculate request args
@@ -43,9 +44,9 @@ def from_method(self, method, fail=False):
43
44
44
45
# execute pre and post hooks in order
45
46
for contract in reversed (contracts ):
46
- request = contract .add_pre_hook (request , fail )
47
+ request = contract .add_pre_hook (request , results )
47
48
for contract in contracts :
48
- request = contract .add_post_hook (request , fail )
49
+ request = contract .add_post_hook (request , results )
49
50
50
51
return request
51
52
@@ -54,49 +55,67 @@ class Contract(object):
54
55
""" Abstract class for contracts """
55
56
56
57
def __init__ (self , method , * args ):
57
- self .method = method
58
+ self .testcase_pre = self .create_testcase (method , 'pre-hook' )
59
+ self .testcase_post = self .create_testcase (method , 'post-hook' )
58
60
self .args = args
59
61
60
- def add_pre_hook (self , request , fail = False ):
61
- cb = request .callback
62
-
63
- @wraps (cb )
64
- def wrapper (response ):
65
- try :
66
- self .pre_process (response )
67
- except ContractFail as e :
68
- if fail :
69
- raise
62
+ def create_testcase (self , method , hook ):
63
+ spider = method .__self__ .name
64
+
65
+ class ContractTestCase (TestCase ):
66
+ def __str__ (_self ):
67
+ return "[%s] %s (@%s %s)" % (spider , method .__name__ , self .name , hook )
68
+
69
+ name = '%s_%s' % (spider , method .__name__ )
70
+ setattr (ContractTestCase , name , lambda x : x )
71
+ return ContractTestCase (name )
72
+
73
+ def add_pre_hook (self , request , results ):
74
+ if hasattr (self , 'pre_process' ):
75
+ cb = request .callback
76
+
77
+ @wraps (cb )
78
+ def wrapper (response ):
79
+ try :
80
+ results .startTest (self .testcase_pre )
81
+ self .pre_process (response )
82
+ results .stopTest (self .testcase_pre )
83
+ except AssertionError :
84
+ results .addFailure (self .testcase_pre , sys .exc_info ())
85
+ except Exception :
86
+ results .addError (self .testcase_pre , sys .exc_info ())
70
87
else :
71
- print e .format (self .method )
72
- return list (iterate_spider_output (cb (response )))
88
+ results .addSuccess (self .testcase_pre )
89
+ finally :
90
+ return list (iterate_spider_output (cb (response )))
91
+
92
+ request .callback = wrapper
73
93
74
- request .callback = wrapper
75
94
return request
76
95
77
- def add_post_hook (self , request , fail = False ):
78
- cb = request .callback
79
-
80
- @wraps (cb )
81
- def wrapper (response ):
82
- output = list (iterate_spider_output (cb (response )))
83
- try :
84
- self .post_process (output )
85
- except ContractFail as e :
86
- if fail :
87
- raise
96
+ def add_post_hook (self , request , results ):
97
+ if hasattr (self , 'post_process' ):
98
+ cb = request .callback
99
+
100
+ @wraps (cb )
101
+ def wrapper (response ):
102
+ try :
103
+ output = list (iterate_spider_output (cb (response )))
104
+ results .startTest (self .testcase_post )
105
+ self .post_process (output )
106
+ results .stopTest (self .testcase_post )
107
+ except AssertionError :
108
+ results .addFailure (self .testcase_post , sys .exc_info ())
109
+ except Exception :
110
+ results .addError (self .testcase_post , sys .exc_info ())
88
111
else :
89
- print e .format (self .method )
90
- return output
112
+ results .addSuccess (self .testcase_post )
113
+ finally :
114
+ return output
115
+
116
+ request .callback = wrapper
91
117
92
- request .callback = wrapper
93
118
return request
94
119
95
120
def adjust_request_args (self , args ):
96
121
return args
97
-
98
- def pre_process (self , response ):
99
- pass
100
-
101
- def post_process (self , output ):
102
- pass
0 commit comments