Merge lp:~elopio/selenium-simple-test/print_elements into lp:selenium-simple-test
- print_elements
- Merge into trunk
Status: | Merged |
---|---|
Approved by: | Vincent Ladeuil |
Approved revision: | 376 |
Merged at revision: | 370 |
Proposed branch: | lp:~elopio/selenium-simple-test/print_elements |
Merge into: | lp:selenium-simple-test |
Prerequisite: | lp:~elopio/selenium-simple-test/fix1166408-assert_text_with_no_text |
Diff against target: |
361 lines (+121/-56) 5 files modified
src/sst/actions.py (+54/-41) src/sst/selftests/assert_text.py (+2/-13) src/sst/selftests/element_to_string.py (+19/-0) src/sst/tests/test_actions.py (+44/-2) src/testproject/templates/index.html (+2/-0) |
To merge this branch: | bzr merge lp:~elopio/selenium-simple-test/print_elements |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Vincent Ladeuil (community) | Approve | ||
Review via email:
|
Commit message
Added _element_to_string to get a printable version of the element.
Description of the change
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Leo Arias (elopio) wrote : | # |
<elopio> vila: please take a look at http://
<vila> elopio: hehe, even shorter ! So you don't need the mock ones anymore right ? <evil grin>
<elopio> vila: I disagree with you there :)
<vila> elopio: I'm all ears
<elopio> vila: this tests are nice to have, but they don't test a unit of code, they are retesting things that are already tested in selenium, they depend on firefox to run, they are slower, and the set up for the test is done on an external file (index.html), thus are not as readable as the other ones.
<vila> elopio: ha, then don't write them this way
<elopio> vila: now I'm all ears ;)
<elopio> vila: the way to solve all those problems is with a unit test and mock. I agree there are some code paths not tested on the original
<elopio> for example, _get_text
<vila> elopio: your implementation could be more testable but it would mean to not rely as much on actions.py then to be able to test it with a simple hmtl snippet
<vila> elopio: didn't you implemented some helpers to get there without involving firefox ?
<elopio> vila: no, firefox is always needed. I tried with htmlunit, but it sucks.
<elopio> we could do something with phantomjs.
<elopio> that would make it faster than firefox, but still slower than the mocked unit test.
<vila> the mocked one is faster because it does less, but you don't get a clear idea of what 'less' means by just reading the tests, you need to know the implementation to write them which is... bad
<elopio> vila: I wrote them before implementing them.
<vila> elopio: knowing how the implementation will work as opposed to knowing only the API
<vila> elopio: you test actions.
<vila> elopio: how do you know they are related ?
<elopio> knowing what the function does, not how it is implemented.
<elopio> it is a really low level function, so it's implementation is straight-forward.
<elopio> but the implementation could change, what the tests describe is what it does. When there's no id attribute, then get the text.
<elopio> lets say we have a way to test an html snipped without a huge delay
<elopio> then
<elopio> element = mock.Mock()
<elopio> element.
<elopio> element.text = 'Test text'
<elopio> would be the same as
<elopio> element = '<p>Test text</p>'
<elopio> the latter is shorter and clearer, I agree.
<vila> elopio: no, the later is shor.. see ?
<vila> elopio: moreover, even after reading the mock tests thrice, I still don't get what they do, if I really want to understand, I need to look at the implementation
<vila> elopio: and I still don't understand why there is a if in test_element_
<elopio> vila: maybe I can make them clearer, for example making a function called get_element_
<vila> elopio: you'll end up duplicating the implementation which is even worse ;)
<elopio> no, let me try.
<elopio> vila: here: http://
<elopio> once we have a beautifulsoup sele...
![](/+icing/build/overlay/assets/skins/sam/images/close.gif)
Vincent Ladeuil (vila) : | # |
Preview Diff
1 | === modified file 'src/sst/actions.py' | |||
2 | --- src/sst/actions.py 2013-04-09 15:25:02 +0000 | |||
3 | +++ src/sst/actions.py 2013-04-10 15:27:28 +0000 | |||
4 | @@ -453,7 +453,7 @@ | |||
5 | 453 | _make_results_dir() | 453 | _make_results_dir() |
6 | 454 | browsermob_proxy.save_har(_make_useable_har_name()) | 454 | browsermob_proxy.save_har(_make_useable_har_name()) |
7 | 455 | 455 | ||
9 | 456 | 456 | ||
10 | 457 | def assert_checkbox(id_or_elem): | 457 | def assert_checkbox(id_or_elem): |
11 | 458 | """ | 458 | """ |
12 | 459 | Assert that the element is a checkbox. | 459 | Assert that the element is a checkbox. |
13 | @@ -473,23 +473,54 @@ | |||
14 | 473 | or isn't a checkbox.""" | 473 | or isn't a checkbox.""" |
15 | 474 | checkbox = assert_checkbox(id_or_elem) | 474 | checkbox = assert_checkbox(id_or_elem) |
16 | 475 | real = checkbox.is_selected() | 475 | real = checkbox.is_selected() |
18 | 476 | msg = 'Checkbox: %r - Has Value: %r' % (_get_text(checkbox), real) | 476 | msg = 'Checkbox: %r - Has Value: %r' % (_element_to_string(checkbox), real) |
19 | 477 | if real != value: | 477 | if real != value: |
20 | 478 | _raise(msg) | 478 | _raise(msg) |
21 | 479 | 479 | ||
22 | 480 | 480 | ||
23 | 481 | def _element_to_string(element): | ||
24 | 482 | element_id = element.get_attribute('id') | ||
25 | 483 | if element_id: | ||
26 | 484 | return element_id | ||
27 | 485 | else: | ||
28 | 486 | element_text = _get_text(element) | ||
29 | 487 | if element_text: | ||
30 | 488 | return element_text | ||
31 | 489 | else: | ||
32 | 490 | return element.get_attribute('outerHTML') | ||
33 | 491 | |||
34 | 492 | |||
35 | 493 | def _get_text(elem): | ||
36 | 494 | text = None | ||
37 | 495 | try: | ||
38 | 496 | text = elem.text | ||
39 | 497 | except InvalidElementStateException: | ||
40 | 498 | pass | ||
41 | 499 | if text: | ||
42 | 500 | # Note that some elements (like textfields) return empty string | ||
43 | 501 | # for text and we still need to call value | ||
44 | 502 | return text | ||
45 | 503 | try: | ||
46 | 504 | text = elem.get_attribute('value') | ||
47 | 505 | except InvalidElementStateException: | ||
48 | 506 | pass | ||
49 | 507 | return text | ||
50 | 508 | |||
51 | 509 | |||
52 | 510 | |||
53 | 481 | def toggle_checkbox(id_or_elem): | 511 | def toggle_checkbox(id_or_elem): |
54 | 482 | """ | 512 | """ |
55 | 483 | Toggle the checkbox value. Takes an element id or object. Raises a failure | 513 | Toggle the checkbox value. Takes an element id or object. Raises a failure |
56 | 484 | exception if the element specified doesn't exist or isn't a checkbox.""" | 514 | exception if the element specified doesn't exist or isn't a checkbox.""" |
57 | 485 | checkbox = assert_checkbox(id_or_elem) | 515 | checkbox = assert_checkbox(id_or_elem) |
59 | 486 | logger.debug('Toggling checkbox: %r' % _get_text(checkbox)) | 516 | element_string = _element_to_string(checkbox) |
60 | 517 | logger.debug('Toggling checkbox: %r' % element_string) | ||
61 | 487 | before = checkbox.is_selected() | 518 | before = checkbox.is_selected() |
62 | 488 | checkbox.click() | 519 | checkbox.click() |
63 | 489 | after = checkbox.is_selected() | 520 | after = checkbox.is_selected() |
64 | 490 | msg = 'Checkbox: %r - was not toggled, value remains: %r' \ | ||
65 | 491 | % (_get_text(checkbox), before) | ||
66 | 492 | if before == after: | 521 | if before == after: |
67 | 522 | msg = 'Checkbox: %r - was not toggled, value remains: %r' \ | ||
68 | 523 | % (element_string, before) | ||
69 | 493 | _raise(msg) | 524 | _raise(msg) |
70 | 494 | 525 | ||
71 | 495 | 526 | ||
72 | @@ -499,7 +530,8 @@ | |||
73 | 499 | exception if the element specified doesn't exist or isn't a checkbox.""" | 530 | exception if the element specified doesn't exist or isn't a checkbox.""" |
74 | 500 | checkbox = assert_checkbox(id_or_elem) | 531 | checkbox = assert_checkbox(id_or_elem) |
75 | 501 | logger.debug( | 532 | logger.debug( |
77 | 502 | 'Setting checkbox %r to %r' % (_get_text(checkbox), new_value)) | 533 | 'Setting checkbox %r to %r' % (_element_to_string(checkbox), |
78 | 534 | new_value)) | ||
79 | 503 | # There is no method to 'unset' a checkbox in the browser object | 535 | # There is no method to 'unset' a checkbox in the browser object |
80 | 504 | current_value = checkbox.is_selected() | 536 | current_value = checkbox.is_selected() |
81 | 505 | if new_value != current_value: | 537 | if new_value != current_value: |
82 | @@ -526,7 +558,7 @@ | |||
83 | 526 | """ | 558 | """ |
84 | 527 | key_element = _get_elem(id_or_elem) | 559 | key_element = _get_elem(id_or_elem) |
85 | 528 | msg = 'Simulating keypress on %r with %r key' \ | 560 | msg = 'Simulating keypress on %r with %r key' \ |
87 | 529 | % (_get_text(key_element), key_to_press) | 561 | % (_element_to_string(key_element), key_to_press) |
88 | 530 | logger.debug(msg) | 562 | logger.debug(msg) |
89 | 531 | key_code = _make_keycode(key_to_press) | 563 | key_code = _make_keycode(key_to_press) |
90 | 532 | key_element.send_keys(key_code) | 564 | key_element.send_keys(key_code) |
91 | @@ -558,7 +590,7 @@ | |||
92 | 558 | off by passing `clear=False`.""" | 590 | off by passing `clear=False`.""" |
93 | 559 | textfield = assert_textfield(id_or_elem) | 591 | textfield = assert_textfield(id_or_elem) |
94 | 560 | msg = 'Writing to textfield %r with text %r' \ | 592 | msg = 'Writing to textfield %r with text %r' \ |
96 | 561 | % (_get_text(textfield), new_text) | 593 | % (_element_to_string(textfield), new_text) |
97 | 562 | logger.debug(msg) | 594 | logger.debug(msg) |
98 | 563 | 595 | ||
99 | 564 | # clear field like this, don't use clear() | 596 | # clear field like this, don't use clear() |
100 | @@ -576,7 +608,7 @@ | |||
101 | 576 | current_text = textfield.get_attribute('value') | 608 | current_text = textfield.get_attribute('value') |
102 | 577 | if current_text != new_text: | 609 | if current_text != new_text: |
103 | 578 | msg = 'Textfield: %r - did not write. Text was: %r' \ | 610 | msg = 'Textfield: %r - did not write. Text was: %r' \ |
105 | 579 | % (_get_text(textfield), current_text) | 611 | % (_element_to_string(textfield), current_text) |
106 | 580 | _raise(msg) | 612 | _raise(msg) |
107 | 581 | 613 | ||
108 | 582 | 614 | ||
109 | @@ -589,7 +621,7 @@ | |||
110 | 589 | link = _get_elem(id_or_elem) | 621 | link = _get_elem(id_or_elem) |
111 | 590 | if link.tag_name != 'a': | 622 | if link.tag_name != 'a': |
112 | 591 | msg = 'The text %r is not part of a Link or a Link ID' \ | 623 | msg = 'The text %r is not part of a Link or a Link ID' \ |
114 | 592 | % _get_text(link) | 624 | % _element_to_string(link) |
115 | 593 | _raise(msg) | 625 | _raise(msg) |
116 | 594 | return link | 626 | return link |
117 | 595 | 627 | ||
118 | @@ -623,7 +655,7 @@ | |||
119 | 623 | _logger.debug('Capturing http traffic...') | 655 | _logger.debug('Capturing http traffic...') |
120 | 624 | browsermob_proxy.new_har() | 656 | browsermob_proxy.new_har() |
121 | 625 | 657 | ||
123 | 626 | logger.debug('Clicking link %r' % _get_text(link)) | 658 | logger.debug('Clicking link %r' % _element_to_string(link)) |
124 | 627 | link.click() | 659 | link.click() |
125 | 628 | 660 | ||
126 | 629 | if wait: | 661 | if wait: |
127 | @@ -667,7 +699,7 @@ | |||
128 | 667 | logger.debug('Capturing http traffic...') | 699 | logger.debug('Capturing http traffic...') |
129 | 668 | browsermob_proxy.new_har() | 700 | browsermob_proxy.new_har() |
130 | 669 | 701 | ||
132 | 670 | logger.debug('Clicking element %r' % _get_text(elem)) | 702 | logger.debug('Clicking element %r' % _element_to_string(elem)) |
133 | 671 | elem.click() | 703 | elem.click() |
134 | 672 | 704 | ||
135 | 673 | if wait: | 705 | if wait: |
136 | @@ -904,7 +936,8 @@ | |||
137 | 904 | """Set the select drop-list to a text or value specified.""" | 936 | """Set the select drop-list to a text or value specified.""" |
138 | 905 | elem = assert_dropdown(id_or_elem) | 937 | elem = assert_dropdown(id_or_elem) |
139 | 906 | logger.debug( | 938 | logger.debug( |
141 | 907 | 'Setting %r option list to %r' % (_get_text(elem), text or value)) | 939 | 'Setting %r option list to %r' % (_element_to_string(elem), |
142 | 940 | text or value)) | ||
143 | 908 | if text and not value: | 941 | if text and not value: |
144 | 909 | for element in elem.find_elements_by_tag_name('option'): | 942 | for element in elem.find_elements_by_tag_name('option'): |
145 | 910 | if element.text == text: | 943 | if element.text == text: |
146 | @@ -958,7 +991,7 @@ | |||
147 | 958 | a radio button""" | 991 | a radio button""" |
148 | 959 | elem = assert_radio(id_or_elem) | 992 | elem = assert_radio(id_or_elem) |
149 | 960 | selected = elem.is_selected() | 993 | selected = elem.is_selected() |
151 | 961 | msg = 'Radio %r should be set to: %s.' % (_get_text(elem), value) | 994 | msg = 'Radio %r should be set to: %s.' % (_element_to_string(elem), value) |
152 | 962 | if value != selected: | 995 | if value != selected: |
153 | 963 | _raise(msg) | 996 | _raise(msg) |
154 | 964 | 997 | ||
155 | @@ -966,27 +999,10 @@ | |||
156 | 966 | def set_radio_value(id_or_elem): | 999 | def set_radio_value(id_or_elem): |
157 | 967 | """Select the specified radio button.""" | 1000 | """Select the specified radio button.""" |
158 | 968 | elem = assert_radio(id_or_elem) | 1001 | elem = assert_radio(id_or_elem) |
160 | 969 | logger.debug('Selecting radio button item %r' % _get_text(elem)) | 1002 | logger.debug('Selecting radio button item %r' % _element_to_string(elem)) |
161 | 970 | elem.click() | 1003 | elem.click() |
162 | 971 | 1004 | ||
163 | 972 | 1005 | ||
164 | 973 | def _get_text(elem): | ||
165 | 974 | text = None | ||
166 | 975 | try: | ||
167 | 976 | text = elem.text | ||
168 | 977 | except InvalidElementStateException: | ||
169 | 978 | pass | ||
170 | 979 | if text: | ||
171 | 980 | # Note that some elements (like textfields) return empty string | ||
172 | 981 | # for text and we still need to call value | ||
173 | 982 | return text | ||
174 | 983 | try: | ||
175 | 984 | text = elem.get_attribute('value') | ||
176 | 985 | except InvalidElementStateException: | ||
177 | 986 | pass | ||
178 | 987 | return text | ||
179 | 988 | |||
180 | 989 | |||
181 | 990 | def assert_text(id_or_elem, text): | 1006 | def assert_text(id_or_elem, text): |
182 | 991 | """ | 1007 | """ |
183 | 992 | Assert the specified element text is as specified. | 1008 | Assert the specified element text is as specified. |
184 | @@ -996,11 +1012,7 @@ | |||
185 | 996 | elem = _get_elem(id_or_elem) | 1012 | elem = _get_elem(id_or_elem) |
186 | 997 | real = _get_text(elem) | 1013 | real = _get_text(elem) |
187 | 998 | if real is None: | 1014 | if real is None: |
193 | 999 | if isinstance(id_or_elem, str): | 1015 | msg = 'Element %r has no text attribute' % _element_to_string(elem) |
189 | 1000 | element_string = id_or_elem | ||
190 | 1001 | else: | ||
191 | 1002 | element_string = elem.get_attribute('outerHTML') | ||
192 | 1003 | msg = 'Element %r has no text attribute' % element_string | ||
194 | 1004 | _raise(msg) | 1016 | _raise(msg) |
195 | 1005 | if real != text: | 1017 | if real != text: |
196 | 1006 | msg = 'Element text should be %r. It is %r.' % (text, real) | 1018 | msg = 'Element text should be %r. It is %r.' % (text, real) |
197 | @@ -1015,7 +1027,7 @@ | |||
198 | 1015 | elem = _get_elem(id_or_elem) | 1027 | elem = _get_elem(id_or_elem) |
199 | 1016 | real = _get_text(elem) | 1028 | real = _get_text(elem) |
200 | 1017 | if real is None: | 1029 | if real is None: |
202 | 1018 | msg = 'Element %r has no text attribute' % _get_text(elem) | 1030 | msg = 'Element %r has no text attribute' % _element_to_string(elem) |
203 | 1019 | _raise(msg) | 1031 | _raise(msg) |
204 | 1020 | msg = 'Element text is %r. Does not contain %r' % (real, text) | 1032 | msg = 'Element text is %r. Does not contain %r' % (real, text) |
205 | 1021 | if regex: | 1033 | if regex: |
206 | @@ -1173,7 +1185,7 @@ | |||
207 | 1173 | logger.debug('Capturing http traffic...') | 1185 | logger.debug('Capturing http traffic...') |
208 | 1174 | browsermob_proxy.new_har() | 1186 | browsermob_proxy.new_har() |
209 | 1175 | 1187 | ||
211 | 1176 | logger.debug('Clicking button %r' % _get_text(button)) | 1188 | logger.debug('Clicking button %r' % _element_to_string(button)) |
212 | 1177 | button.click() | 1189 | button.click() |
213 | 1178 | 1190 | ||
214 | 1179 | if wait: | 1191 | if wait: |
215 | @@ -1420,7 +1432,8 @@ | |||
216 | 1420 | the attribute using a regular expression search. | 1432 | the attribute using a regular expression search. |
217 | 1421 | """ | 1433 | """ |
218 | 1422 | elem = _get_elem(id_or_elem) | 1434 | elem = _get_elem(id_or_elem) |
220 | 1423 | logger.debug('Checking attribute %r of %r' % (attribute, _get_text(elem))) | 1435 | logger.debug( |
221 | 1436 | 'Checking attribute %r of %r' % (attribute, _element_to_string(elem))) | ||
222 | 1424 | actual = elem.get_attribute(attribute) | 1437 | actual = elem.get_attribute(attribute) |
223 | 1425 | if not regex: | 1438 | if not regex: |
224 | 1426 | success = value == actual | 1439 | success = value == actual |
225 | @@ -1442,7 +1455,7 @@ | |||
226 | 1442 | elem = _get_elem(id_or_elem) | 1455 | elem = _get_elem(id_or_elem) |
227 | 1443 | logger.debug( | 1456 | logger.debug( |
228 | 1444 | 'Checking css property %r: %r of %r' % ( | 1457 | 'Checking css property %r: %r of %r' % ( |
230 | 1445 | property, value, _get_text(elem))) | 1458 | property, value, _element_to_string(elem))) |
231 | 1446 | actual = elem.value_of_css_property(property) | 1459 | actual = elem.value_of_css_property(property) |
232 | 1447 | # some browsers return string with space padded commas, some don't. | 1460 | # some browsers return string with space padded commas, some don't. |
233 | 1448 | actual = actual.replace(', ', ',') | 1461 | actual = actual.replace(', ', ',') |
234 | 1449 | 1462 | ||
235 | === modified file 'src/sst/selftests/assert_text.py' | |||
236 | --- src/sst/selftests/assert_text.py 2013-04-09 15:25:02 +0000 | |||
237 | +++ src/sst/selftests/assert_text.py 2013-04-10 15:27:28 +0000 | |||
238 | @@ -14,22 +14,11 @@ | |||
239 | 14 | # Test wrong text. | 14 | # Test wrong text. |
240 | 15 | fails(assert_text, 'some_id', 'Wrong text') | 15 | fails(assert_text, 'some_id', 'Wrong text') |
241 | 16 | 16 | ||
243 | 17 | # Test no text with id. | 17 | # Test no text. |
244 | 18 | try: | 18 | try: |
245 | 19 | assert_text('element_without_text', '') | 19 | assert_text('element_without_text', '') |
246 | 20 | except AssertionError as error: | 20 | except AssertionError as error: |
247 | 21 | assert_equal( | 21 | assert_equal( |
260 | 22 | "Element 'element_without_text' has no text attribute", error.message) | 22 | "Element u'element_without_text' has no text attribute", error.message) |
249 | 23 | else: | ||
250 | 24 | raise AssertionError('assert_text did not fail.') | ||
251 | 25 | |||
252 | 26 | # Test no text with element. | ||
253 | 27 | try: | ||
254 | 28 | assert_text(get_element(id='element_without_text'), '') | ||
255 | 29 | except AssertionError as error: | ||
256 | 30 | expected_message = ("Element u\'<p id=\"element_without_text\"></p>\' " | ||
257 | 31 | "has no text attribute") | ||
258 | 32 | assert_equal( | ||
259 | 33 | expected_message, error.message) | ||
261 | 34 | else: | 23 | else: |
262 | 35 | raise AssertionError('assert_text did not fail.') | 24 | raise AssertionError('assert_text did not fail.') |
263 | 36 | 25 | ||
264 | === added file 'src/sst/selftests/element_to_string.py' | |||
265 | --- src/sst/selftests/element_to_string.py 1970-01-01 00:00:00 +0000 | |||
266 | +++ src/sst/selftests/element_to_string.py 2013-04-10 15:27:28 +0000 | |||
267 | @@ -0,0 +1,19 @@ | |||
268 | 1 | import sst.actions | ||
269 | 2 | |||
270 | 3 | |||
271 | 4 | sst.actions.go_to('/') | ||
272 | 5 | sst.actions.assert_title('The Page Title') | ||
273 | 6 | |||
274 | 7 | element_with_id = sst.actions.get_element(id='some_id') | ||
275 | 8 | element_string = sst.actions._element_to_string(element_with_id) | ||
276 | 9 | sst.actions.assert_equal('some_id', element_string) | ||
277 | 10 | |||
278 | 11 | element_without_id_with_text = sst.actions.get_element(css_class='no_id') | ||
279 | 12 | element_string = sst.actions._element_to_string(element_without_id_with_text) | ||
280 | 13 | sst.actions.assert_equal('Element without id, with text.', element_string) | ||
281 | 14 | |||
282 | 15 | element_without_id_without_text = sst.actions.get_element( | ||
283 | 16 | css_class='no_id_no_text') | ||
284 | 17 | element_string = sst.actions._element_to_string( | ||
285 | 18 | element_without_id_without_text) | ||
286 | 19 | sst.actions.assert_equal('<p class="no_id_no_text"></p>', element_string) | ||
287 | 0 | 20 | ||
288 | === modified file 'src/sst/tests/test_actions.py' | |||
289 | --- src/sst/tests/test_actions.py 2013-02-11 19:03:51 +0000 | |||
290 | +++ src/sst/tests/test_actions.py 2013-04-10 15:27:28 +0000 | |||
291 | @@ -20,10 +20,9 @@ | |||
292 | 20 | from cStringIO import StringIO | 20 | from cStringIO import StringIO |
293 | 21 | import logging | 21 | import logging |
294 | 22 | 22 | ||
296 | 23 | 23 | import mock | |
297 | 24 | import testtools | 24 | import testtools |
298 | 25 | 25 | ||
299 | 26 | |||
300 | 27 | from sst import actions | 26 | from sst import actions |
301 | 28 | 27 | ||
302 | 29 | 28 | ||
303 | @@ -64,3 +63,46 @@ | |||
304 | 64 | def test_wait_for_retries(self): | 63 | def test_wait_for_retries(self): |
305 | 65 | self.assertRaisesOnlyOnce(None, actions.wait_for, | 64 | self.assertRaisesOnlyOnce(None, actions.wait_for, |
306 | 66 | self.raise_stale_element) | 65 | self.raise_stale_element) |
307 | 66 | |||
308 | 67 | |||
309 | 68 | class TestElementToString(testtools.TestCase): | ||
310 | 69 | |||
311 | 70 | def test_element_with_id(self): | ||
312 | 71 | element = self._get_element_with_id(element_id='Test id') | ||
313 | 72 | self.assertEqual('Test id', actions._element_to_string(element)) | ||
314 | 73 | |||
315 | 74 | def _get_element_with_id(self, element_id): | ||
316 | 75 | element = mock.Mock() | ||
317 | 76 | def mock_get_attribute(attribute): | ||
318 | 77 | if attribute == 'id': | ||
319 | 78 | return element_id | ||
320 | 79 | element.get_attribute.side_effect = mock_get_attribute | ||
321 | 80 | return element | ||
322 | 81 | |||
323 | 82 | def test_element_without_id_with_text(self): | ||
324 | 83 | element = self._get_element_without_id_with_text(text='Test text') | ||
325 | 84 | self.assertEqual('Test text', actions._element_to_string(element)) | ||
326 | 85 | |||
327 | 86 | def _get_element_without_id_with_text(self, text): | ||
328 | 87 | element = mock.Mock() | ||
329 | 88 | element.get_attribute.return_value = None | ||
330 | 89 | element.text = text | ||
331 | 90 | return element | ||
332 | 91 | |||
333 | 92 | def test_element_without_id_without_text(self): | ||
334 | 93 | element = self._get_element_without_id_without_text(tag='p') | ||
335 | 94 | self.assertEqual( | ||
336 | 95 | '<p></p>', actions._element_to_string(element)) | ||
337 | 96 | |||
338 | 97 | def _get_element_without_id_without_text(self, tag): | ||
339 | 98 | element = mock.Mock() | ||
340 | 99 | def mock_get_attribute(attribute): | ||
341 | 100 | values = { | ||
342 | 101 | 'id': None, | ||
343 | 102 | 'value': None, | ||
344 | 103 | 'outerHTML': '<{0}></{0}>'.format(tag) | ||
345 | 104 | } | ||
346 | 105 | return values[attribute] | ||
347 | 106 | element.get_attribute.side_effect = mock_get_attribute | ||
348 | 107 | element.text = None | ||
349 | 108 | return element | ||
350 | 67 | 109 | ||
351 | === modified file 'src/testproject/templates/index.html' | |||
352 | --- src/testproject/templates/index.html 2013-04-09 02:23:36 +0000 | |||
353 | +++ src/testproject/templates/index.html 2013-04-10 15:27:28 +0000 | |||
354 | @@ -15,6 +15,8 @@ | |||
355 | 15 | 15 | ||
356 | 16 | <p class="unique_class" id="some_id">Some text here</p> | 16 | <p class="unique_class" id="some_id">Some text here</p> |
357 | 17 | <p id="element_without_text"></p> | 17 | <p id="element_without_text"></p> |
358 | 18 | <p class="no_id">Element without id, with text.</p> | ||
359 | 19 | <p class="no_id_no_text"></p> | ||
360 | 18 | <p class="some_class">More text</p> | 20 | <p class="some_class">More text</p> |
361 | 19 | <p class="some_class">And yet more</p> | 21 | <p class="some_class">And yet more</p> |
362 | 20 | 22 |
I don't think this is a good use of mock. It at least triggers my main reluctance about using it: the tests using mock in this proposal are not doubled with tests using the real code.
Can you try rewriting those tests ?