Merge lp:~nik90/ubuntu-clock-app/reorganise-stopwatch-tests into lp:ubuntu-clock-app/saucy
- reorganise-stopwatch-tests
- Merge into saucy
Status: | Merged |
---|---|
Approved by: | Leo Arias |
Approved revision: | 360 |
Merged at revision: | 355 |
Proposed branch: | lp:~nik90/ubuntu-clock-app/reorganise-stopwatch-tests |
Merge into: | lp:ubuntu-clock-app/saucy |
Diff against target: |
300 lines (+132/-106) 3 files modified
stopwatch/LapList.qml (+1/-0) tests/autopilot/ubuntu_clock_app/emulators.py (+82/-28) tests/autopilot/ubuntu_clock_app/tests/test_stopwatch.py (+49/-78) |
To merge this branch: | bzr merge lp:~nik90/ubuntu-clock-app/reorganise-stopwatch-tests |
Related bugs: |
Reviewer | Review Type | Date Requested | Status |
---|---|---|---|
Ubuntu Phone Apps Jenkins Bot | continuous-integration | Approve | |
Leo Arias (community) | code review | Approve | |
Review via email: mp+208475@code.launchpad.net |
Commit message
Refactor stopwatch helpers to follow the page object pattern.
Description of the change
Refactor stopwatch helpers to follow the page object pattern. Tested on both phone and tablet interface.
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
Nekhelesh Ramananthan (nik90) wrote : | # |
The jenkins failure above is not a clock AP issue.
Leo Arias (elopio) wrote : | # |
75 + def get_stopwatch_
76 + """Returns the stopwatch time label"""
77 + return self.wait_
This is actually an implementation detail, the fact that the stop watch time is kept in a label called label. The service your UI is providing to the users is to give them the time of the stopwatch, so that's what we should return in the public helpers, instead of a label element.
So, this would be better:
def get_stopwatch_
return self.wait_
That way, if you or a designer decide to show the time in a component called 'Timer' that has a 'time' property instead of a 'Label' component with a 'text' property, you will only have to change one line and all your tests will keep working.
Now, on:
83 + @autopilot_
84 + def get_stopwatch_
What you want is the element so you can later delete it, right?
So, this method should be kept private, to be sure that it's not in use by any tests in case you need to refactor it.
I'd say _get_stopwatch_
And about the log_action decorator, what's nice is to put it only on the actions a user does. Like go_to_some_page, or save_something, or delete_something. We don't really need to log any method that starts with get_something, because they are only used as lower level helpers to perform an action, or as things that you would assert on a test. I'm not sure if I'm being clear, if not, let me know on the chat. Also, feel free to disagree, this is not an exact science and we are just inventing things here :)
93 + def start_stopwatch
107 + def reset_stopwatch
117 + def create_lap(self):
These need a log_action ^
A small detail is that the docstring of methods "prescribes the function or method's effect as a command", so instead of a verb like Returns, it should be Return. And instead of "Function to stop..." it should be "Stop..."
This comes from pep257. http://
- 356. By Nekhelesh Ramananthan
-
Returned proper time instead of label
- 357. By Nekhelesh Ramananthan
-
Added autopilot loggers to the public functions and renamed get_stopwatch_lap function
- 358. By Nekhelesh Ramananthan
-
Fixed comments according to pep257 standards
Leo Arias (elopio) wrote : | # |
227 + def test_start_
234 + def test_stop_
By looking just at the UI, there isn't really a start and a stop button. Well, they are there, but that's an implementation detail that we know because we have read the code.
From a user story point of view, I think this would be clearer named as something like:
test_click_
test_click_
If that last name makes the line longer than 80 characters, then it could be just:
test_click_
240 + self.assertThat(
241 + stopwatch_time,
242 + NotEquals(
I think that one is not necessary because in essence it would be the same check we are doing on the previous tests, I think.
What if we do something like this:
stopwatch_
time.sleep(1)
self.assertThat(
stopwatch_
Equals(
The eventually is not needed in there, btw.
Nekhelesh Ramananthan (nik90) wrote : | # |
>
> So, this would be better:
>
> def get_stopwatch_
> return self.wait_
>
> That way, if you or a designer decide to show the time in a component called
> 'Timer' that has a 'time' property instead of a 'Label' component with a
> 'text' property, you will only have to change one line and all your tests will
> keep working.
>
I actually had in mind, but forgot it at the last second :)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
FAILED: Continuous integration, rev:358
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
- 359. By Nekhelesh Ramananthan
-
Clarified test names and fixed failing test
- 360. By Nekhelesh Ramananthan
-
Fixed stop stopwatch test
Leo Arias (elopio) wrote : | # |
I like this so much, I'll print it ;)
Nekhelesh Ramananthan (nik90) wrote : | # |
;)
Ubuntu Phone Apps Jenkins Bot (ubuntu-phone-apps-jenkins-bot) wrote : | # |
PASSED: Continuous integration, rev:360
http://
Executed test runs:
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild:
http://
Preview Diff
1 | === modified file 'stopwatch/LapList.qml' |
2 | --- stopwatch/LapList.qml 2014-02-18 20:09:55 +0000 |
3 | +++ stopwatch/LapList.qml 2014-02-27 00:04:13 +0000 |
4 | @@ -52,6 +52,7 @@ |
5 | |
6 | ListView { |
7 | id: listViewLap |
8 | + objectName: "listStopwatchLaps" |
9 | |
10 | clip: true |
11 | anchors { left: parent.left; right: parent.right; } |
12 | |
13 | === modified file 'tests/autopilot/ubuntu_clock_app/emulators.py' |
14 | --- tests/autopilot/ubuntu_clock_app/emulators.py 2014-02-26 21:06:47 +0000 |
15 | +++ tests/autopilot/ubuntu_clock_app/emulators.py 2014-02-27 00:04:13 +0000 |
16 | @@ -55,6 +55,16 @@ |
17 | self.switch_to_tab('AlarmTab') |
18 | return self.wait_select_single(AlarmPage) |
19 | |
20 | + @autopilot_logging.log_action(logger.info) |
21 | + def open_stopwatch(self): |
22 | + """Open the Stopwatch Tab. |
23 | + |
24 | + :return the Stopwatch page. |
25 | + |
26 | + """ |
27 | + self.switch_to_tab('StopwatchTab') |
28 | + return self.wait_select_single(StopwatchPage) |
29 | + |
30 | # Common Emulator Functions |
31 | def _drag_page(self, page, direction): |
32 | """Function to drag the page up/down""" |
33 | @@ -141,34 +151,6 @@ |
34 | return self.wait_select_single( |
35 | "Standard", objectName="savedworldcity0") |
36 | |
37 | - # STOPWATCH Page Emulator Functions |
38 | - def get_stopwatch_label(self): |
39 | - """Returns the select for the stopwatch label""" |
40 | - return self.select_single( |
41 | - "StopwatchPage").wait_select_single("Label", objectName="label") |
42 | - |
43 | - def get_stopwatch_button(self): |
44 | - """Returns the select for the stopwatch button""" |
45 | - return self.wait_select_single( |
46 | - "StopwatchFace", objectName="stopwatchFace") |
47 | - |
48 | - def get_lap_button(self): |
49 | - """Returns the select for the lap button""" |
50 | - return self.wait_select_single("ImageButton", objectName="lapButton") |
51 | - |
52 | - def get_reset_button(self): |
53 | - """Returns the select for the reset button""" |
54 | - return self.wait_select_single("ImageButton", objectName="resetButton") |
55 | - |
56 | - def get_num_of_laps(self): |
57 | - """Returns the number of laps in the stopwatch page.""" |
58 | - stopwatch_page = self.select_single("StopwatchPage") |
59 | - return int(stopwatch_page.wait_select_single("QQuickListView").count) |
60 | - |
61 | - def get_first_laps_list_item(self): |
62 | - """Returns the first lap list item in the stopwatch page.""" |
63 | - return self.wait_select_single("Standard", objectName="laps0") |
64 | - |
65 | |
66 | class LabelDots(toolkit_emulators.TextField): |
67 | """Autopilot helper for the LabelDots component.""" |
68 | @@ -214,6 +196,78 @@ |
69 | objectName='animationContainer').moving.wait_for(False) |
70 | |
71 | |
72 | +class StopwatchPage(Page): |
73 | + """Autopilot helper for the Stopwatch page.""" |
74 | + |
75 | + def get_stopwatch_time(self): |
76 | + """Return the stopwatch time""" |
77 | + return self.wait_select_single('Label', objectName='label').text |
78 | + |
79 | + def get_num_of_laps(self): |
80 | + """Return the number of laps in the stopwatch page.""" |
81 | + return int(self.wait_select_single('QQuickListView').count) |
82 | + |
83 | + def _get_stopwatch_lap_list_element(self, index): |
84 | + """Return a lap list item in the stopwatch page. |
85 | + |
86 | + :param index: stopwatch lap number |
87 | + |
88 | + """ |
89 | + return self.wait_select_single( |
90 | + 'Standard', objectName='laps{}'.format(index)) |
91 | + |
92 | + @autopilot_logging.log_action(logger.info) |
93 | + def start_stopwatch(self): |
94 | + """Start the stopwatch""" |
95 | + self._click_start_stop_stopwatch_button() |
96 | + |
97 | + @autopilot_logging.log_action(logger.info) |
98 | + def stop_stopwatch(self): |
99 | + """Stop the stopwatch""" |
100 | + self._click_start_stop_stopwatch_button() |
101 | + |
102 | + def _click_start_stop_stopwatch_button(self): |
103 | + """Click the start/stop stopwatch button""" |
104 | + start_stop_button = self.wait_select_single( |
105 | + 'StopwatchFace', objectName='stopwatchFace') |
106 | + self.pointing_device.click_object(start_stop_button) |
107 | + |
108 | + @autopilot_logging.log_action(logger.info) |
109 | + def reset_stopwatch(self): |
110 | + """Reset the stopwatch""" |
111 | + self._click_reset_stopwatch_button() |
112 | + |
113 | + def _click_reset_stopwatch_button(self): |
114 | + """Click the reset stopwatch button""" |
115 | + reset_button = self.wait_select_single( |
116 | + 'ImageButton', objectName='resetButton') |
117 | + self.pointing_device.click_object(reset_button) |
118 | + |
119 | + @autopilot_logging.log_action(logger.info) |
120 | + def create_lap(self): |
121 | + """Create a stopwatch lap""" |
122 | + self._click_lap_stopwatch_button() |
123 | + |
124 | + def _click_lap_stopwatch_button(self): |
125 | + """Click the stopwatch lap button""" |
126 | + lap_button = self.wait_select_single( |
127 | + 'ImageButton', objectName='lapButton') |
128 | + self.pointing_device.click_object(lap_button) |
129 | + |
130 | + @autopilot_logging.log_action(logger.info) |
131 | + def delete_lap(self, index): |
132 | + """Delete stopwatch lap |
133 | + |
134 | + :param index: stopwatch lap number |
135 | + |
136 | + """ |
137 | + lap = self._get_stopwatch_lap_list_element(index=index) |
138 | + if not self.main_view.wideAspect: |
139 | + self.drag_page_up() |
140 | + lap.swipe_to_delete() |
141 | + lap.confirm_removal() |
142 | + |
143 | + |
144 | class AlarmPage(Page): |
145 | """Autopilot helper for the Alarm page.""" |
146 | |
147 | |
148 | === modified file 'tests/autopilot/ubuntu_clock_app/tests/test_stopwatch.py' |
149 | --- tests/autopilot/ubuntu_clock_app/tests/test_stopwatch.py 2014-02-19 12:03:16 +0000 |
150 | +++ tests/autopilot/ubuntu_clock_app/tests/test_stopwatch.py 2014-02-27 00:04:13 +0000 |
151 | @@ -20,100 +20,71 @@ |
152 | |
153 | from __future__ import absolute_import |
154 | |
155 | -from testtools.matchers import Equals, NotEquals, Is, Not |
156 | +import time |
157 | +from testtools.matchers import Equals, NotEquals |
158 | from autopilot.matchers import Eventually |
159 | |
160 | from ubuntu_clock_app.tests import ClockAppTestCase |
161 | |
162 | + |
163 | class TestStopwatch(ClockAppTestCase): |
164 | """Tests the stopwatch page features""" |
165 | |
166 | - """ This is needed to wait for the application to start. |
167 | - In the testfarm, the application may take some time to show up.""" |
168 | def setUp(self): |
169 | + """ This is needed to wait for the application to start. |
170 | + |
171 | + In the testfarm, the application may take some time to show up. |
172 | + |
173 | + """ |
174 | super(TestStopwatch, self).setUp() |
175 | self.assertThat( |
176 | self.main_view.visible, Eventually(Equals(True))) |
177 | |
178 | - # Move to stopwatch tab |
179 | - self.main_view.switch_to_tab("StopwatchTab") |
180 | - |
181 | - def tearDown(self): |
182 | - super(TestStopwatch, self).tearDown() |
183 | - |
184 | - def create_lap(self): |
185 | - """Function to create a stopwatch lap""" |
186 | - lap_button = self.main_view.get_lap_button() |
187 | - self.pointing_device.click_object(lap_button) |
188 | - |
189 | - def start_stop_stopwatch(self): |
190 | - """Function to start/stop the stopwatch""" |
191 | - start_stop_button = self.main_view.get_stopwatch_button() |
192 | - self.pointing_device.click_object(start_stop_button) |
193 | - |
194 | - def test_start_stop_reset_stopwatch(self): |
195 | - """Test to check the proper functioning of the start/stop/reset of stopwatch""" |
196 | - |
197 | - stopwatch_label = self.main_view.get_stopwatch_label() |
198 | - reset_button = self.main_view.get_reset_button() |
199 | - |
200 | - # Start the stopwatch and check if the stopwatch starts ticking |
201 | - stopwatch_label_before = self.main_view.get_stopwatch_label().text |
202 | - self.start_stop_stopwatch() |
203 | - self.assertThat(stopwatch_label.text, Eventually(NotEquals("00:00.0"))) |
204 | - |
205 | - # Stop the stopwatch and check it has indeed stopped |
206 | - self.start_stop_stopwatch() |
207 | - self.assertThat(stopwatch_label_before, NotEquals(self.main_view.get_stopwatch_label().text)) |
208 | - stopwatch_label_after = lambda: self.main_view.get_stopwatch_label().text |
209 | - self.assertThat(stopwatch_label_after, Eventually(Equals(self.main_view.get_stopwatch_label().text))) |
210 | - |
211 | - # Press reset and check if the stopwatch has been resetted |
212 | - self.pointing_device.click_object(reset_button) |
213 | - self.assertThat(stopwatch_label.text, Eventually(Equals("00:00.0"))) |
214 | - |
215 | - def test_create_lap(self): |
216 | - """Test to check creating a new stopwatch lap""" |
217 | - |
218 | - # Start the stopwatch |
219 | - stopwatch_label = self.main_view.get_stopwatch_label().text |
220 | - self.start_stop_stopwatch() |
221 | - |
222 | - # Ensure that the stopwatch actually ticks |
223 | - self.assertThat(stopwatch_label, Eventually(NotEquals("00:00.0"))) |
224 | - |
225 | - # Create a stopwatch lap by pressing the lap button |
226 | - num_of_laps_old = self.main_view.get_num_of_laps() |
227 | - self.create_lap() |
228 | - |
229 | + self.page = self.main_view.open_stopwatch() |
230 | + |
231 | + def test_click_clock_center_must_start_stopwatch(self): |
232 | + """Test if start button starts the stopwatch""" |
233 | + stopwatch_time = self.page.get_stopwatch_time() |
234 | + self.page.start_stopwatch() |
235 | + # Check the stopwatch started running |
236 | + self.assertThat(stopwatch_time, Eventually(NotEquals('00:00.0'))) |
237 | + |
238 | + def test_click_clock_center_with_stopwatch_started_must_stop_it(self): |
239 | + """Test if stop button stops the stopwatch""" |
240 | + self.page.start_stopwatch() |
241 | + self.page.stop_stopwatch() |
242 | + # Check that the stopwatch has stopped |
243 | + stopwatch_time = self.page.get_stopwatch_time() |
244 | + time.sleep(1) |
245 | + self.assertThat( |
246 | + stopwatch_time, |
247 | + Equals(self.page.get_stopwatch_time())) |
248 | + |
249 | + def test_restart_button_must_restart_stopwatch_time(self): |
250 | + """Test if reset button resets the stopwatch time""" |
251 | + self.page.start_stopwatch() |
252 | + stopwatch_time = self.page.get_stopwatch_time() |
253 | + self.page.reset_stopwatch() |
254 | + # Check that the stopwatch has been reset |
255 | + self.assertThat(stopwatch_time, Eventually(Equals('00:00.0'))) |
256 | + |
257 | + def test_lap_button_must_create_stopwatch_lap(self): |
258 | + """Test if lap button creates a stopwatch lap""" |
259 | + self.page.start_stopwatch() |
260 | + num_of_laps_old = self.page.get_num_of_laps() |
261 | + self.page.create_lap() |
262 | # Confirm that the lap is created |
263 | self.assertThat( |
264 | - self.main_view.get_num_of_laps, |
265 | + self.page.get_num_of_laps, |
266 | Eventually(Equals(num_of_laps_old + 1))) |
267 | |
268 | - def test_delete_lap(self): |
269 | - """Test to check deleting a stopwatch lap""" |
270 | - |
271 | - # Start the stopwatch |
272 | - stopwatch_label = self.main_view.get_stopwatch_label().text |
273 | - self.start_stop_stopwatch() |
274 | - |
275 | - # Ensure that the stopwatch actually ticks |
276 | - self.assertThat(stopwatch_label, Eventually(NotEquals("00:00.0"))) |
277 | - |
278 | - # Create a stopwatch lap |
279 | - self.create_lap() |
280 | - |
281 | - num_of_laps_old = self.main_view.get_num_of_laps() |
282 | - if not(self.main_view.wideAspect): |
283 | - self.main_view.drag_page_up("StopwatchPage") |
284 | - |
285 | - # Delete stopwatch lap |
286 | - first_lap = self.main_view.get_first_laps_list_item() |
287 | - first_lap.swipe_to_delete() |
288 | - first_lap.confirm_removal() |
289 | - |
290 | + def test_delete_lap_must_delete_from_stopwatch_lap_list(self): |
291 | + """Test to delete a lap and check if it has been removed properly""" |
292 | + self.page.start_stopwatch() |
293 | + self.page.create_lap() |
294 | + num_of_laps_old = self.page.get_num_of_laps() |
295 | + self.page.delete_lap(index=0) |
296 | # Check that the stopwatch lap has been deleted |
297 | self.assertThat( |
298 | - self.main_view.get_num_of_laps, |
299 | + self.page.get_num_of_laps, |
300 | Eventually(Equals(num_of_laps_old - 1))) |
FAILED: Continuous integration, rev:355 91.189. 93.70:8080/ job/ubuntu- clock-app- ci/293/ 91.189. 93.70:8080/ job/generic- mediumtests- trusty/ 1518 91.189. 93.70:8080/ job/ubuntu- clock-app- raring- amd64-ci/ 293 91.189. 93.70:8080/ job/ubuntu- clock-app- saucy-amd64- ci/293 91.189. 93.70:8080/ job/ubuntu- clock-app- trusty- amd64-ci/ 211
http://
Executed test runs:
UNSTABLE: http://
SUCCESS: http://
SUCCESS: http://
SUCCESS: http://
Click here to trigger a rebuild: 91.189. 93.70:8080/ job/ubuntu- clock-app- ci/293/ rebuild
http://