Commit 631a27fe0dad5aca229f4186385488aad4662bee
0 parents
Exists in
master
first commit
Showing
51 changed files
with
5323 additions
and
0 deletions
Show diff stats
.idea/apiTest.iml
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | <module type="PYTHON_MODULE" version="4"> | ||
3 | <component name="NewModuleRootManager"> | ||
4 | <content url="file://$MODULE_DIR$" /> | ||
5 | <orderEntry type="inheritedJdk" /> | ||
6 | <orderEntry type="sourceFolder" forTests="false" /> | ||
7 | </component> | ||
8 | <component name="TestRunnerService"> | ||
9 | <option name="PROJECT_TEST_RUNNER" value="Unittests" /> | ||
10 | </component> | ||
11 | </module> |
.idea/inspectionProfiles/Project_Default.xml
File was created | 1 | <component name="InspectionProjectProfileManager"> | |
2 | <profile version="1.0"> | ||
3 | <option name="myName" value="Project Default" /> | ||
4 | <inspection_tool class="PyUnresolvedReferencesInspection" enabled="true" level="WARNING" enabled_by_default="true"> | ||
5 | <option name="ignoredIdentifiers"> | ||
6 | <list> | ||
7 | <option value="elecCard_setUp" /> | ||
8 | </list> | ||
9 | </option> | ||
10 | </inspection_tool> | ||
11 | </profile> | ||
12 | </component> |
.idea/misc.xml
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | <project version="4"> | ||
3 | <component name="ProjectRootManager" version="2" project-jdk-name="Python 3.6.2 (/Library/Frameworks/Python.framework/Versions/3.6/bin/python3.6)" project-jdk-type="Python SDK" /> | ||
4 | </project> |
.idea/modules.xml
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | <project version="4"> | ||
3 | <component name="ProjectModuleManager"> | ||
4 | <modules> | ||
5 | <module fileurl="file://$PROJECT_DIR$/.idea/apiTest.iml" filepath="$PROJECT_DIR$/.idea/apiTest.iml" /> | ||
6 | </modules> | ||
7 | </component> | ||
8 | </project> |
.idea/vcs.xml
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | <project version="4"> | ||
3 | <component name="VcsDirectoryMappings"> | ||
4 | <mapping directory="$PROJECT_DIR$" vcs="Git" /> | ||
5 | </component> | ||
6 | </project> |
.idea/workspace.xml
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | <project version="4"> | ||
3 | <component name="ChangeListManager"> | ||
4 | <list default="true" id="33187cb8-da74-4b13-8a55-31c4cae60a20" name="Default" comment="" /> | ||
5 | <option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" /> | ||
6 | <option name="TRACKING_ENABLED" value="true" /> | ||
7 | <option name="SHOW_DIALOG" value="false" /> | ||
8 | <option name="HIGHLIGHT_CONFLICTS" value="true" /> | ||
9 | <option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" /> | ||
10 | <option name="LAST_RESOLUTION" value="IGNORE" /> | ||
11 | </component> | ||
12 | <component name="CoverageDataManager"> | ||
13 | <SUITE FILE_PATH="coverage/apiTest$debugggggg.coverage" NAME="debugggggg Coverage Results" MODIFIED="1514886595342" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$/test_cases" /> | ||
14 | <SUITE FILE_PATH="coverage/apiTest$run_test.coverage" NAME="run_test Coverage Results" MODIFIED="1515151494257" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" /> | ||
15 | </component> | ||
16 | <component name="DatabaseView"> | ||
17 | <option name="SHOW_INTERMEDIATE" value="true" /> | ||
18 | <option name="GROUP_SCHEMA" value="true" /> | ||
19 | <option name="GROUP_CONTENTS" value="false" /> | ||
20 | <option name="SORT_POSITIONED" value="false" /> | ||
21 | <option name="SHOW_TABLE_DETAILS" value="true" /> | ||
22 | <option name="SHOW_EMPTY_GROUPS" value="false" /> | ||
23 | <option name="AUTO_SCROLL_FROM_SOURCE" value="false" /> | ||
24 | <expand /> | ||
25 | <select /> | ||
26 | </component> | ||
27 | <component name="FileEditorManager"> | ||
28 | <leaf SIDE_TABS_SIZE_LIMIT_KEY="300"> | ||
29 | <file leaf-file-name="mysql_db.py" pinned="false" current-in-tab="false"> | ||
30 | <entry file="file://$PROJECT_DIR$/data_fixture/mysql_db.py"> | ||
31 | <provider selected="true" editor-type-id="text-editor"> | ||
32 | <state relative-caret-position="34"> | ||
33 | <caret line="2" column="0" lean-forward="true" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" /> | ||
34 | <folding> | ||
35 | <marker date="1514616463000" expanded="true" signature="1672:1692" ph="select * fro... " /> | ||
36 | <marker date="1514616463000" expanded="true" signature="1672:1694" ph="select * fro... missing_value" /> | ||
37 | <marker date="1514616463000" expanded="true" signature="1672:1718" ph="select count... missing_value" /> | ||
38 | <marker date="1514616463000" expanded="true" signature="1672:1719" ph="select count... missing_value" /> | ||
39 | </folding> | ||
40 | </state> | ||
41 | </provider> | ||
42 | </entry> | ||
43 | </file> | ||
44 | <file leaf-file-name="app_record_statistic.py" pinned="false" current-in-tab="false"> | ||
45 | <entry file="file://$PROJECT_DIR$/test_cases/app_record_statistic.py"> | ||
46 | <provider selected="true" editor-type-id="text-editor"> | ||
47 | <state relative-caret-position="761"> | ||
48 | <caret line="170" column="45" lean-forward="false" selection-start-line="170" selection-start-column="45" selection-end-line="170" selection-end-column="45" /> | ||
49 | <folding> | ||
50 | <element signature="e#47#62#0" expanded="true" /> | ||
51 | </folding> | ||
52 | </state> | ||
53 | </provider> | ||
54 | </entry> | ||
55 | </file> | ||
56 | <file leaf-file-name="run_test.py" pinned="false" current-in-tab="true"> | ||
57 | <entry file="file://$PROJECT_DIR$/run_test.py"> | ||
58 | <provider selected="true" editor-type-id="text-editor"> | ||
59 | <state relative-caret-position="289"> | ||
60 | <caret line="17" column="0" lean-forward="true" selection-start-line="17" selection-start-column="0" selection-end-line="17" selection-end-column="0" /> | ||
61 | <folding> | ||
62 | <element signature="e#47#62#0" expanded="true" /> | ||
63 | </folding> | ||
64 | </state> | ||
65 | </provider> | ||
66 | </entry> | ||
67 | </file> | ||
68 | <file leaf-file-name="debugggggg.py" pinned="false" current-in-tab="false"> | ||
69 | <entry file="file://$PROJECT_DIR$/test_cases/debugggggg.py"> | ||
70 | <provider selected="true" editor-type-id="text-editor"> | ||
71 | <state relative-caret-position="34"> | ||
72 | <caret line="2" column="0" lean-forward="false" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" /> | ||
73 | <folding /> | ||
74 | </state> | ||
75 | </provider> | ||
76 | </entry> | ||
77 | </file> | ||
78 | <file leaf-file-name="subject_sync.py" pinned="false" current-in-tab="false"> | ||
79 | <entry file="file://$PROJECT_DIR$/test_cases/subject_sync.py"> | ||
80 | <provider selected="true" editor-type-id="text-editor"> | ||
81 | <state relative-caret-position="85"> | ||
82 | <caret line="5" column="66" lean-forward="true" selection-start-line="5" selection-start-column="66" selection-end-line="5" selection-end-column="66" /> | ||
83 | <folding /> | ||
84 | </state> | ||
85 | </provider> | ||
86 | </entry> | ||
87 | </file> | ||
88 | <file leaf-file-name="create_testdata.py" pinned="false" current-in-tab="false"> | ||
89 | <entry file="file://$PROJECT_DIR$/data_fixture/create_testdata.py"> | ||
90 | <provider selected="true" editor-type-id="text-editor"> | ||
91 | <state relative-caret-position="310"> | ||
92 | <caret line="356" column="79" lean-forward="false" selection-start-line="356" selection-start-column="67" selection-end-line="356" selection-end-column="79" /> | ||
93 | <folding> | ||
94 | <element signature="e#47#83#0" expanded="true" /> | ||
95 | <marker date="1515219431000" expanded="true" signature="1421:1488" ph="select * fro... ozing_customermachine" /> | ||
96 | <marker date="1515219431000" expanded="true" signature="1421:1489" ph="select * fro... ozing_customermachine" /> | ||
97 | <marker date="1515219431000" expanded="true" signature="1421:1491" ph="select * fro... ozing_customermachine" /> | ||
98 | <marker date="1515219431000" expanded="true" signature="1421:1492" ph="select * fro... ozing_customermachine" /> | ||
99 | <marker date="1515219431000" expanded="true" signature="1421:1518" ph="select * fro... ozing_customermachine" /> | ||
100 | <marker date="1515219431000" expanded="true" signature="1549:1608" ph="SELECT * FRO... ozing_machine" /> | ||
101 | <marker date="1515219431000" expanded="true" signature="1549:1609" ph="SELECT * FRO... ozing_machine" /> | ||
102 | <marker date="1515219431000" expanded="true" signature="1549:1612" ph="SELECT * FRO... ozing_machine" /> | ||
103 | <marker date="1515219431000" expanded="true" signature="1549:1613" ph="SELECT * FRO... ozing_machine" /> | ||
104 | <marker date="1515219431000" expanded="true" signature="1549:1639" ph="SELECT * FRO... ozing_machine" /> | ||
105 | <marker date="1515219431000" expanded="true" signature="1752:2214" ph="insert into acornuser.ozing_customermachine... " /> | ||
106 | <marker date="1515219431000" expanded="true" signature="2928:2997" ph="SELECT * FRO... ozing_samplemachine" /> | ||
107 | <marker date="1515219431000" expanded="true" signature="3049:3113" ph="SELECT * FRO... ozing_machine" /> | ||
108 | <marker date="1515219431000" expanded="true" signature="4735:4806" ph="select * fro... ozing_customermachine" /> | ||
109 | <marker date="1515219431000" expanded="true" signature="5151:5215" ph="SELECT * FRO... ozing_machine" /> | ||
110 | <marker date="1515219431000" expanded="true" signature="5276:5356" ph="SELECT * FRO... ozing_machine" /> | ||
111 | <marker date="1515219431000" expanded="true" signature="6222:6293" ph="select * fro... ozing_customermachine" /> | ||
112 | <marker date="1515219431000" expanded="true" signature="6578:6641" ph="select * fro... ozing_machine" /> | ||
113 | <marker date="1515219431000" expanded="true" signature="7715:7780" ph="update acorn... " /> | ||
114 | <marker date="1515219431000" expanded="true" signature="7715:7804" ph="update acorn... " /> | ||
115 | <marker date="1515219431000" expanded="true" signature="7928:8009" ph="select * fro... child_user" /> | ||
116 | <marker date="1515219431000" expanded="true" signature="8075:8156" ph="select * fro... child_user" /> | ||
117 | <marker date="1515219431000" expanded="true" signature="8075:8203" ph="select * fro... child_user" /> | ||
118 | <marker date="1515219431000" expanded="true" signature="8075:8205" ph="select * fro... child_user" /> | ||
119 | <marker date="1515219431000" expanded="true" signature="9093:9178" ph="select * fro... acorn_user_status" /> | ||
120 | <marker date="1515219431000" expanded="true" signature="9320:9420" ph="select * fro... acorn_user_status" /> | ||
121 | <marker date="1515219431000" expanded="true" signature="10158:10258" ph="select * fro... acorn_user_status" /> | ||
122 | <marker date="1515219431000" expanded="true" signature="11302:11360" ph="select * fro... acorn_user_extra" /> | ||
123 | <marker date="1515219431000" expanded="true" signature="11397:11483" ph="select * fro... acorn_user_extra" /> | ||
124 | <marker date="1515219431000" expanded="true" signature="11914:11983" ph="select * fro... subAccount_user_extra" /> | ||
125 | <marker date="1515219431000" expanded="true" signature="11914:11984" ph="select * fro... subAccount_user_extra" /> | ||
126 | <marker date="1515219431000" expanded="true" signature="11914:11988" ph="select * fro... subAccount_user_extra" /> | ||
127 | <marker date="1515219431000" expanded="true" signature="12023:12092" ph="select * fro... subAccount_user_extra" /> | ||
128 | <marker date="1515219431000" expanded="true" signature="12023:12122" ph="select * fro... subAccount_user_extra" /> | ||
129 | <marker date="1515219431000" expanded="true" signature="12023:12138" ph="select * fro... subAccount_user_extra" /> | ||
130 | <marker date="1515219431000" expanded="true" signature="13348:13448" ph="select * fro... ozing_student" /> | ||
131 | <marker date="1515219431000" expanded="true" signature="13550:13636" ph="update acorn... " /> | ||
132 | <marker date="1515219431000" expanded="true" signature="13550:13638" ph="update acorn... " /> | ||
133 | <marker date="1515219431000" expanded="true" signature="13726:13834" ph="select * fro... ozing_student" /> | ||
134 | <marker date="1515219431000" expanded="true" signature="15966:16006" ph="select max(i... acorn_user" /> | ||
135 | <marker date="1515219431000" expanded="true" signature="15966:16008" ph="select max(i... acorn_user" /> | ||
136 | <marker date="1515219431000" expanded="true" signature="16721:16796" ph="select passw... parents_space_pass" /> | ||
137 | <marker date="1515219431000" expanded="true" signature="17752:17804" ph="update analy... " /> | ||
138 | <marker date="1515219431000" expanded="true" signature="17752:17821" ph="update analy... " /> | ||
139 | <marker date="1515219431000" expanded="true" signature="17752:17849" ph="update analy... " /> | ||
140 | <marker date="1515219431000" expanded="true" signature="17752:17850" ph="update analy... " /> | ||
141 | </folding> | ||
142 | </state> | ||
143 | </provider> | ||
144 | </entry> | ||
145 | </file> | ||
146 | <file leaf-file-name="config_data.py" pinned="false" current-in-tab="false"> | ||
147 | <entry file="file://$PROJECT_DIR$/data_fixture/config_data.py"> | ||
148 | <provider selected="true" editor-type-id="text-editor"> | ||
149 | <state relative-caret-position="114"> | ||
150 | <caret line="12" column="14" lean-forward="false" selection-start-line="12" selection-start-column="14" selection-end-line="12" selection-end-column="14" /> | ||
151 | <folding /> | ||
152 | </state> | ||
153 | </provider> | ||
154 | </entry> | ||
155 | </file> | ||
156 | </leaf> | ||
157 | </component> | ||
158 | <component name="FileTemplateManagerImpl"> | ||
159 | <option name="RECENT_TEMPLATES"> | ||
160 | <list> | ||
161 | <option value="Python Script" /> | ||
162 | </list> | ||
163 | </option> | ||
164 | </component> | ||
165 | <component name="FindInProjectRecents"> | ||
166 | <findStrings> | ||
167 | <find>_generate_report</find> | ||
168 | <find>Data</find> | ||
169 | <find>test_unbindCard_success</find> | ||
170 | <find>login</find> | ||
171 | <find>DEVICE_NUMBER_EDIT_PHONE</find> | ||
172 | <find>pre_SetUpElecCard</find> | ||
173 | <find>authCode</find> | ||
174 | <find>subaccountswitch001</find> | ||
175 | <find>pre_AddSubAccount</find> | ||
176 | <find>parent_id</find> | ||
177 | <find>USER_ID</find> | ||
178 | <find>USER_PHONE_EDIT</find> | ||
179 | <find>RegisterExtrainfoCheck</find> | ||
180 | <find>png</find> | ||
181 | <find>checkSignatureExists</find> | ||
182 | <find>SUB_ACC_GET_ID_1</find> | ||
183 | <find>SUB_ACC_GET_ID_</find> | ||
184 | <find>SUB_ACC_DEL_ID_2</find> | ||
185 | <find>SUB_ACC_SWITCH_ID_1</find> | ||
186 | <find>SUB_ACC</find> | ||
187 | <find>pre_subAccount</find> | ||
188 | <find>pre_elecCard</find> | ||
189 | <find>保卡</find> | ||
190 | <find>'time_spend'</find> | ||
191 | <find>select_</find> | ||
192 | <find>Data.DEVICE_NUMBER_CUS_BIND</find> | ||
193 | <find>SUB_ACC_</find> | ||
194 | <find>test_getAppRecordOneday_success</find> | ||
195 | <find>get_parentSpace_password</find> | ||
196 | <find>print</find> | ||
197 | </findStrings> | ||
198 | <replaceStrings> | ||
199 | <replace>app_pid</replace> | ||
200 | <replace>'app_pid'</replace> | ||
201 | <replace>'time_spent'</replace> | ||
202 | <replace>user_id</replace> | ||
203 | <replace>device_number</replace> | ||
204 | <replace>PARENT_ID</replace> | ||
205 | </replaceStrings> | ||
206 | <dirStrings> | ||
207 | <dir>$PROJECT_DIR$</dir> | ||
208 | </dirStrings> | ||
209 | </component> | ||
210 | <component name="IdeDocumentHistory"> | ||
211 | <option name="CHANGED_PATHS"> | ||
212 | <list> | ||
213 | <option value="$PROJECT_DIR$/tests/elecCard.py" /> | ||
214 | <option value="$PROJECT_DIR$/db_fixture/mysql_db.py" /> | ||
215 | <option value="$PROJECT_DIR$/tests/configParse'.py" /> | ||
216 | <option value="$PROJECT_DIR$/tests/configParse.py" /> | ||
217 | <option value="$PROJECT_DIR$/tests/personalCenter/elecCardFlow_test.py" /> | ||
218 | <option value="$PROJECT_DIR$/tests/personalCenter/elecCard_setUp.py" /> | ||
219 | <option value="$PROJECT_DIR$/tests/personalCenter/elecCard/elecCard_setUp.py" /> | ||
220 | <option value="$PROJECT_DIR$/tests/personalCenter/elecCard/elecCard_check.py" /> | ||
221 | <option value="$PROJECT_DIR$/tests/test_suites/test_elecCard.py" /> | ||
222 | <option value="$PROJECT_DIR$/tests/test_cases/__init__.py" /> | ||
223 | <option value="$PROJECT_DIR$/test_suites/test_elecCard.py" /> | ||
224 | <option value="$PROJECT_DIR$/data_fixture/UthCode.py" /> | ||
225 | <option value="/Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/HtmlTestRunner/runner.py" /> | ||
226 | <option value="$PROJECT_DIR$/config.ini" /> | ||
227 | <option value="$PROJECT_DIR$/HTMLTestRunner.py" /> | ||
228 | <option value="$PROJECT_DIR$/test_cases/elecCard_check.py" /> | ||
229 | <option value="$PROJECT_DIR$/data_fixture/authCode.py" /> | ||
230 | <option value="$PROJECT_DIR$/test_cases/elecCard_setUp.py" /> | ||
231 | <option value="$PROJECT_DIR$/data_fixture/test_verify.py" /> | ||
232 | <option value="$PROJECT_DIR$/test_cases/region_grade_school.py" /> | ||
233 | <option value="$PROJECT_DIR$/test_cases/eleccard_setUp.py" /> | ||
234 | <option value="$PROJECT_DIR$/test_cases/press.py" /> | ||
235 | <option value="$PROJECT_DIR$/test_cases/sub_account.py" /> | ||
236 | <option value="$PROJECT_DIR$/test_cases/register.py" /> | ||
237 | <option value="$PROJECT_DIR$/test_cases/personal_info.py" /> | ||
238 | <option value="$PROJECT_DIR$/data_fixture/config_data.py" /> | ||
239 | <option value="$PROJECT_DIR$/data_fixture/mysql_db.py" /> | ||
240 | <option value="$PROJECT_DIR$/test_cases/parent_space.py" /> | ||
241 | <option value="$PROJECT_DIR$/test_cases/xueketongbu.py" /> | ||
242 | <option value="$PROJECT_DIR$/test_cases/app_record_statistic.py" /> | ||
243 | <option value="$PROJECT_DIR$/data_fixture/create_testdata.py" /> | ||
244 | <option value="$PROJECT_DIR$/test_cases/debugggggg.py" /> | ||
245 | <option value="$PROJECT_DIR$/run_test.py" /> | ||
246 | <option value="$PROJECT_DIR$/test_cases/__init__.py" /> | ||
247 | <option value="$PROJECT_DIR$/data_fixture/__init__.py" /> | ||
248 | <option value="$PROJECT_DIR$/test_cases/subject_sync.py" /> | ||
249 | </list> | ||
250 | </option> | ||
251 | </component> | ||
252 | <component name="JsBuildToolGruntFileManager" detection-done="true" sorting="DEFINITION_ORDER" /> | ||
253 | <component name="JsBuildToolPackageJson" detection-done="true" sorting="DEFINITION_ORDER" /> | ||
254 | <component name="JsGulpfileManager"> | ||
255 | <detection-done>true</detection-done> | ||
256 | <sorting>DEFINITION_ORDER</sorting> | ||
257 | </component> | ||
258 | <component name="ProjectFrameBounds" extendedState="6"> | ||
259 | <option name="x" value="23" /> | ||
260 | <option name="y" value="85" /> | ||
261 | <option name="width" value="1920" /> | ||
262 | <option name="height" value="977" /> | ||
263 | </component> | ||
264 | <component name="ProjectView"> | ||
265 | <navigator currentView="ProjectPane" proportions="" version="1"> | ||
266 | <flattenPackages /> | ||
267 | <showMembers /> | ||
268 | <showModules /> | ||
269 | <showLibraryContents /> | ||
270 | <hideEmptyPackages /> | ||
271 | <abbreviatePackageNames /> | ||
272 | <autoscrollToSource /> | ||
273 | <autoscrollFromSource /> | ||
274 | <sortByType /> | ||
275 | <manualOrder /> | ||
276 | <foldersAlwaysOnTop value="true" /> | ||
277 | </navigator> | ||
278 | <panes> | ||
279 | <pane id="Scope" /> | ||
280 | <pane id="ProjectPane"> | ||
281 | <subPane> | ||
282 | <expand> | ||
283 | <path> | ||
284 | <item name="apiTest" type="b2602c69:ProjectViewProjectNode" /> | ||
285 | <item name="apiTest" type="462c0819:PsiDirectoryNode" /> | ||
286 | </path> | ||
287 | <path> | ||
288 | <item name="apiTest" type="b2602c69:ProjectViewProjectNode" /> | ||
289 | <item name="apiTest" type="462c0819:PsiDirectoryNode" /> | ||
290 | <item name="data_fixture" type="462c0819:PsiDirectoryNode" /> | ||
291 | </path> | ||
292 | <path> | ||
293 | <item name="apiTest" type="b2602c69:ProjectViewProjectNode" /> | ||
294 | <item name="apiTest" type="462c0819:PsiDirectoryNode" /> | ||
295 | <item name="report" type="462c0819:PsiDirectoryNode" /> | ||
296 | </path> | ||
297 | <path> | ||
298 | <item name="apiTest" type="b2602c69:ProjectViewProjectNode" /> | ||
299 | <item name="apiTest" type="462c0819:PsiDirectoryNode" /> | ||
300 | <item name="test_cases" type="462c0819:PsiDirectoryNode" /> | ||
301 | </path> | ||
302 | <path> | ||
303 | <item name="apiTest" type="b2602c69:ProjectViewProjectNode" /> | ||
304 | <item name="apiTest" type="462c0819:PsiDirectoryNode" /> | ||
305 | <item name="test_suites" type="462c0819:PsiDirectoryNode" /> | ||
306 | </path> | ||
307 | </expand> | ||
308 | <select /> | ||
309 | </subPane> | ||
310 | </pane> | ||
311 | <pane id="Scratches" /> | ||
312 | </panes> | ||
313 | </component> | ||
314 | <component name="PropertiesComponent"> | ||
315 | <property name="WebServerToolWindowFactoryState" value="false" /> | ||
316 | <property name="settings.editor.selected.configurable" value="editor.preferences.folding" /> | ||
317 | </component> | ||
318 | <component name="RecentsManager"> | ||
319 | <key name="MoveFile.RECENT_KEYS"> | ||
320 | <recent name="$PROJECT_DIR$/test_cases" /> | ||
321 | <recent name="$PROJECT_DIR$" /> | ||
322 | <recent name="$PROJECT_DIR$/tests" /> | ||
323 | <recent name="$PROJECT_DIR$/tests/test_cases" /> | ||
324 | <recent name="$PROJECT_DIR$/tests/test_cases/personalCenter" /> | ||
325 | </key> | ||
326 | <key name="CopyFile.RECENT_KEYS"> | ||
327 | <recent name="$PROJECT_DIR$/test_cases" /> | ||
328 | <recent name="$PROJECT_DIR$" /> | ||
329 | </key> | ||
330 | </component> | ||
331 | <component name="RunDashboard"> | ||
332 | <option name="ruleStates"> | ||
333 | <list> | ||
334 | <RuleState> | ||
335 | <option name="name" value="ConfigurationTypeDashboardGroupingRule" /> | ||
336 | </RuleState> | ||
337 | <RuleState> | ||
338 | <option name="name" value="StatusDashboardGroupingRule" /> | ||
339 | </RuleState> | ||
340 | </list> | ||
341 | </option> | ||
342 | </component> | ||
343 | <component name="RunManager" selected="Python.run_test"> | ||
344 | <configuration name="debugggggg" type="PythonConfigurationType" factoryName="Python" temporary="true"> | ||
345 | <option name="INTERPRETER_OPTIONS" value="" /> | ||
346 | <option name="PARENT_ENVS" value="true" /> | ||
347 | <envs> | ||
348 | <env name="PYTHONUNBUFFERED" value="1" /> | ||
349 | </envs> | ||
350 | <option name="SDK_HOME" value="" /> | ||
351 | <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$/test_cases" /> | ||
352 | <option name="IS_MODULE_SDK" value="true" /> | ||
353 | <option name="ADD_CONTENT_ROOTS" value="true" /> | ||
354 | <option name="ADD_SOURCE_ROOTS" value="true" /> | ||
355 | <module name="apiTest" /> | ||
356 | <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" /> | ||
357 | <option name="SCRIPT_NAME" value="$PROJECT_DIR$/test_cases/debugggggg.py" /> | ||
358 | <option name="PARAMETERS" value="" /> | ||
359 | <option name="SHOW_COMMAND_LINE" value="false" /> | ||
360 | <option name="EMULATE_TERMINAL" value="false" /> | ||
361 | </configuration> | ||
362 | <configuration name="run_test" type="PythonConfigurationType" factoryName="Python" temporary="true"> | ||
363 | <option name="INTERPRETER_OPTIONS" value="" /> | ||
364 | <option name="PARENT_ENVS" value="true" /> | ||
365 | <envs> | ||
366 | <env name="PYTHONUNBUFFERED" value="1" /> | ||
367 | </envs> | ||
368 | <option name="SDK_HOME" value="" /> | ||
369 | <option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" /> | ||
370 | <option name="IS_MODULE_SDK" value="true" /> | ||
371 | <option name="ADD_CONTENT_ROOTS" value="true" /> | ||
372 | <option name="ADD_SOURCE_ROOTS" value="true" /> | ||
373 | <module name="apiTest" /> | ||
374 | <EXTENSION ID="PythonCoverageRunConfigurationExtension" enabled="false" sample_coverage="true" runner="coverage.py" /> | ||
375 | <option name="SCRIPT_NAME" value="$PROJECT_DIR$/run_test.py" /> | ||
376 | <option name="PARAMETERS" value="" /> | ||
377 | <option name="SHOW_COMMAND_LINE" value="false" /> | ||
378 | <option name="EMULATE_TERMINAL" value="false" /> | ||
379 | </configuration> | ||
380 | <list size="2"> | ||
381 | <item index="0" class="java.lang.String" itemvalue="Python.run_test" /> | ||
382 | <item index="1" class="java.lang.String" itemvalue="Python.debugggggg" /> | ||
383 | </list> | ||
384 | <recent_temporary> | ||
385 | <list size="2"> | ||
386 | <item index="0" class="java.lang.String" itemvalue="Python.run_test" /> | ||
387 | <item index="1" class="java.lang.String" itemvalue="Python.debugggggg" /> | ||
388 | </list> | ||
389 | </recent_temporary> | ||
390 | </component> | ||
391 | <component name="ShelveChangesManager" show_recycled="false"> | ||
392 | <option name="remove_strategy" value="false" /> | ||
393 | </component> | ||
394 | <component name="TaskManager"> | ||
395 | <task active="true" id="Default" summary="Default task"> | ||
396 | <changelist id="33187cb8-da74-4b13-8a55-31c4cae60a20" name="Default" comment="" /> | ||
397 | <created>1512799492607</created> | ||
398 | <option name="number" value="Default" /> | ||
399 | <option name="presentableId" value="Default" /> | ||
400 | <updated>1512799492607</updated> | ||
401 | </task> | ||
402 | <servers /> | ||
403 | </component> | ||
404 | <component name="TodoView"> | ||
405 | <todo-panel id="selected-file"> | ||
406 | <is-autoscroll-to-source value="true" /> | ||
407 | </todo-panel> | ||
408 | <todo-panel id="all"> | ||
409 | <are-packages-shown value="true" /> | ||
410 | <is-autoscroll-to-source value="true" /> | ||
411 | </todo-panel> | ||
412 | </component> | ||
413 | <component name="ToolWindowManager"> | ||
414 | <frame x="-9" y="23" width="1920" height="977" extended-state="6" /> | ||
415 | <editor active="true" /> | ||
416 | <layout> | ||
417 | <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> | ||
418 | <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> | ||
419 | <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> | ||
420 | <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.24829932" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> | ||
421 | <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.2857143" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> | ||
422 | <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="7" side_tool="false" content_ui="tabs" /> | ||
423 | <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.17891374" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> | ||
424 | <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32960597" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> | ||
425 | <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> | ||
426 | <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> | ||
427 | <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" /> | ||
428 | <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4580499" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> | ||
429 | <window_info id="Data View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.2284345" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> | ||
430 | <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> | ||
431 | <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> | ||
432 | <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> | ||
433 | <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> | ||
434 | <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" /> | ||
435 | <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> | ||
436 | </layout> | ||
437 | <layout-to-restore> | ||
438 | <window_info id="TODO" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="6" side_tool="false" content_ui="tabs" /> | ||
439 | <window_info id="Cvs" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> | ||
440 | <window_info id="Message" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> | ||
441 | <window_info id="Commander" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="0" side_tool="false" content_ui="tabs" /> | ||
442 | <window_info id="Event Log" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="7" side_tool="true" content_ui="tabs" /> | ||
443 | <window_info id="Inspection" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.4" sideWeight="0.5" order="5" side_tool="false" content_ui="tabs" /> | ||
444 | <window_info id="Version Control" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="false" weight="0.33" sideWeight="0.5" order="8" side_tool="false" content_ui="tabs" /> | ||
445 | <window_info id="Python Console" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="9" side_tool="false" content_ui="tabs" /> | ||
446 | <window_info id="Run" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.22108844" sideWeight="0.5" order="2" side_tool="false" content_ui="tabs" /> | ||
447 | <window_info id="Terminal" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.32993197" sideWeight="0.5" order="10" side_tool="false" content_ui="tabs" /> | ||
448 | <window_info id="Project" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="true" show_stripe_button="true" weight="0.17571884" sideWeight="0.5" order="0" side_tool="false" content_ui="combo" /> | ||
449 | <window_info id="Hierarchy" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="2" side_tool="false" content_ui="combo" /> | ||
450 | <window_info id="Database" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> | ||
451 | <window_info id="Find" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> | ||
452 | <window_info id="Structure" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> | ||
453 | <window_info id="Ant Build" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.25" sideWeight="0.5" order="1" side_tool="false" content_ui="tabs" /> | ||
454 | <window_info id="Favorites" active="false" anchor="left" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="2" side_tool="true" content_ui="tabs" /> | ||
455 | <window_info id="Debug" active="false" anchor="bottom" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.34807256" sideWeight="0.5" order="3" side_tool="false" content_ui="tabs" /> | ||
456 | <window_info id="Data View" active="false" anchor="right" auto_hide="false" internal_type="DOCKED" type="DOCKED" visible="false" show_stripe_button="true" weight="0.33" sideWeight="0.5" order="4" side_tool="false" content_ui="tabs" /> | ||
457 | </layout-to-restore> | ||
458 | </component> | ||
459 | <component name="TypeScriptGeneratedFilesManager"> | ||
460 | <option name="version" value="1" /> | ||
461 | </component> | ||
462 | <component name="VcsContentAnnotationSettings"> | ||
463 | <option name="myLimit" value="2678400000" /> | ||
464 | </component> | ||
465 | <component name="XDebuggerManager"> | ||
466 | <breakpoint-manager> | ||
467 | <breakpoints> | ||
468 | <line-breakpoint enabled="true" suspend="THREAD" type="python-line"> | ||
469 | <url>file://$PROJECT_DIR$/test_cases/sub_account.py</url> | ||
470 | <line>56</line> | ||
471 | <option name="timeStamp" value="82" /> | ||
472 | </line-breakpoint> | ||
473 | <line-breakpoint enabled="true" suspend="THREAD" type="python-line"> | ||
474 | <url>file://$PROJECT_DIR$/test_cases/register.py</url> | ||
475 | <line>19</line> | ||
476 | <option name="timeStamp" value="102" /> | ||
477 | </line-breakpoint> | ||
478 | <line-breakpoint enabled="true" suspend="THREAD" type="python-line"> | ||
479 | <url>file://$PROJECT_DIR$/test_cases/personal_info.py</url> | ||
480 | <line>253</line> | ||
481 | <option name="timeStamp" value="113" /> | ||
482 | </line-breakpoint> | ||
483 | <line-breakpoint enabled="true" suspend="THREAD" type="python-line"> | ||
484 | <url>file://$PROJECT_DIR$/test_cases/debugggggg.py</url> | ||
485 | <line>18</line> | ||
486 | <option name="timeStamp" value="140" /> | ||
487 | </line-breakpoint> | ||
488 | <line-breakpoint enabled="true" suspend="THREAD" type="python-line"> | ||
489 | <url>file://$PROJECT_DIR$/test_cases/app_record_statistic.py</url> | ||
490 | <line>181</line> | ||
491 | <option name="timeStamp" value="188" /> | ||
492 | </line-breakpoint> | ||
493 | </breakpoints> | ||
494 | <breakpoints-dialog> | ||
495 | <breakpoints-dialog /> | ||
496 | </breakpoints-dialog> | ||
497 | <option name="time" value="189" /> | ||
498 | </breakpoint-manager> | ||
499 | <watches-manager /> | ||
500 | </component> | ||
501 | <component name="editorHistoryManager"> | ||
502 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/suite.py"> | ||
503 | <provider selected="true" editor-type-id="text-editor"> | ||
504 | <state relative-caret-position="1360"> | ||
505 | <caret line="83" column="0" lean-forward="false" selection-start-line="83" selection-start-column="0" selection-end-line="83" selection-end-column="0" /> | ||
506 | <folding /> | ||
507 | </state> | ||
508 | </provider> | ||
509 | </entry> | ||
510 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/codecs.py"> | ||
511 | <provider selected="true" editor-type-id="text-editor"> | ||
512 | <state relative-caret-position="5627"> | ||
513 | <caret line="331" column="0" lean-forward="false" selection-start-line="331" selection-start-column="0" selection-end-line="331" selection-end-column="0" /> | ||
514 | </state> | ||
515 | </provider> | ||
516 | </entry> | ||
517 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/HtmlTestRunner/runner.py" /> | ||
518 | <entry file="file://$PROJECT_DIR$/config.ini" /> | ||
519 | <entry file="file://$PROJECT_DIR$/data_fixture/mysql_db.py"> | ||
520 | <provider selected="true" editor-type-id="text-editor"> | ||
521 | <state relative-caret-position="0"> | ||
522 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="18" selection-end-column="0" /> | ||
523 | <folding> | ||
524 | <marker date="1514616463000" expanded="true" signature="1672:1692" ph="select * fro... " /> | ||
525 | <marker date="1514616463000" expanded="true" signature="1672:1694" ph="select * fro... missing_value" /> | ||
526 | <marker date="1514616463000" expanded="true" signature="1672:1718" ph="select count... missing_value" /> | ||
527 | <marker date="1514616463000" expanded="true" signature="1672:1719" ph="select count... missing_value" /> | ||
528 | </folding> | ||
529 | </state> | ||
530 | </provider> | ||
531 | </entry> | ||
532 | <entry file="file://$PROJECT_DIR$/configParse.py"> | ||
533 | <provider selected="true" editor-type-id="text-editor"> | ||
534 | <state relative-caret-position="238"> | ||
535 | <caret line="16" column="45" lean-forward="false" selection-start-line="16" selection-start-column="45" selection-end-line="16" selection-end-column="45" /> | ||
536 | </state> | ||
537 | </provider> | ||
538 | </entry> | ||
539 | <entry file="file://$PROJECT_DIR$/test_cases/eleccard_setUp.py"> | ||
540 | <provider selected="true" editor-type-id="text-editor"> | ||
541 | <state relative-caret-position="748"> | ||
542 | <caret line="47" column="0" lean-forward="false" selection-start-line="47" selection-start-column="0" selection-end-line="47" selection-end-column="0" /> | ||
543 | <folding /> | ||
544 | </state> | ||
545 | </provider> | ||
546 | </entry> | ||
547 | <entry file="file://$PROJECT_DIR$/test_cases/eleccard_check.py"> | ||
548 | <provider selected="true" editor-type-id="text-editor"> | ||
549 | <state relative-caret-position="816"> | ||
550 | <caret line="51" column="23" lean-forward="false" selection-start-line="51" selection-start-column="23" selection-end-line="51" selection-end-column="23" /> | ||
551 | <folding /> | ||
552 | </state> | ||
553 | </provider> | ||
554 | </entry> | ||
555 | <entry file="file://$PROJECT_DIR$/config.ini" /> | ||
556 | <entry file="file://$PROJECT_DIR$/data_fixture/mysql_db.py"> | ||
557 | <provider selected="true" editor-type-id="text-editor"> | ||
558 | <state relative-caret-position="0"> | ||
559 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="18" selection-end-column="0" /> | ||
560 | <folding> | ||
561 | <marker date="1514616463000" expanded="true" signature="1672:1692" ph="select * fro... " /> | ||
562 | <marker date="1514616463000" expanded="true" signature="1672:1694" ph="select * fro... missing_value" /> | ||
563 | <marker date="1514616463000" expanded="true" signature="1672:1718" ph="select count... missing_value" /> | ||
564 | <marker date="1514616463000" expanded="true" signature="1672:1719" ph="select count... missing_value" /> | ||
565 | </folding> | ||
566 | </state> | ||
567 | </provider> | ||
568 | </entry> | ||
569 | <entry file="file://$PROJECT_DIR$/configParse.py"> | ||
570 | <provider selected="true" editor-type-id="text-editor"> | ||
571 | <state relative-caret-position="272"> | ||
572 | <caret line="16" column="45" lean-forward="true" selection-start-line="16" selection-start-column="45" selection-end-line="16" selection-end-column="45" /> | ||
573 | </state> | ||
574 | </provider> | ||
575 | </entry> | ||
576 | <entry file="file://$PROJECT_DIR$/test_cases/eleccard_setUp.py"> | ||
577 | <provider selected="true" editor-type-id="text-editor"> | ||
578 | <state relative-caret-position="799"> | ||
579 | <caret line="47" column="0" lean-forward="true" selection-start-line="47" selection-start-column="0" selection-end-line="47" selection-end-column="0" /> | ||
580 | <folding /> | ||
581 | </state> | ||
582 | </provider> | ||
583 | </entry> | ||
584 | <entry file="file://$PROJECT_DIR$/test_cases/eleccard_check.py"> | ||
585 | <provider selected="true" editor-type-id="text-editor"> | ||
586 | <state relative-caret-position="867"> | ||
587 | <caret line="51" column="23" lean-forward="true" selection-start-line="51" selection-start-column="23" selection-end-line="51" selection-end-column="23" /> | ||
588 | <folding /> | ||
589 | </state> | ||
590 | </provider> | ||
591 | </entry> | ||
592 | <entry file="file://$PROJECT_DIR$/configParse.py"> | ||
593 | <provider selected="true" editor-type-id="text-editor"> | ||
594 | <state relative-caret-position="0"> | ||
595 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> | ||
596 | </state> | ||
597 | </provider> | ||
598 | </entry> | ||
599 | <entry file="file://$PROJECT_DIR$/tests/test_cases/__init__.py" /> | ||
600 | <entry file="file://$PROJECT_DIR$/configParse.py"> | ||
601 | <provider selected="true" editor-type-id="text-editor"> | ||
602 | <state relative-caret-position="272"> | ||
603 | <caret line="16" column="45" lean-forward="false" selection-start-line="16" selection-start-column="45" selection-end-line="16" selection-end-column="45" /> | ||
604 | </state> | ||
605 | </provider> | ||
606 | </entry> | ||
607 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/codecs.py"> | ||
608 | <provider selected="true" editor-type-id="text-editor"> | ||
609 | <state relative-caret-position="5627"> | ||
610 | <caret line="331" column="0" lean-forward="false" selection-start-line="331" selection-start-column="0" selection-end-line="331" selection-end-column="0" /> | ||
611 | </state> | ||
612 | </provider> | ||
613 | </entry> | ||
614 | <entry file="file://$PROJECT_DIR$/reports/report/Test_region_grade_school.Getrades_2017-12-13_11-29-12.html" /> | ||
615 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/HtmlTestRunner/runner.py" /> | ||
616 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/encodings/ascii.py"> | ||
617 | <provider selected="true" editor-type-id="text-editor"> | ||
618 | <state relative-caret-position="372"> | ||
619 | <caret line="25" column="0" lean-forward="false" selection-start-line="25" selection-start-column="0" selection-end-line="25" selection-end-column="0" /> | ||
620 | </state> | ||
621 | </provider> | ||
622 | </entry> | ||
623 | <entry file="file://$PROJECT_DIR$/config.ini" /> | ||
624 | <entry file="file://$PROJECT_DIR$/HTMLTestRunner.py"> | ||
625 | <provider selected="true" editor-type-id="text-editor"> | ||
626 | <state relative-caret-position="313"> | ||
627 | <caret line="188" column="6" lean-forward="true" selection-start-line="185" selection-start-column="4" selection-end-line="296" selection-end-column="3" /> | ||
628 | <folding> | ||
629 | <element signature="e#8852#10678#0" expanded="false" /> | ||
630 | </folding> | ||
631 | </state> | ||
632 | </provider> | ||
633 | </entry> | ||
634 | <entry file="file://$PROJECT_DIR$/HTMLTestRunner_bak.py"> | ||
635 | <provider selected="true" editor-type-id="text-editor"> | ||
636 | <state relative-caret-position="0"> | ||
637 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> | ||
638 | </state> | ||
639 | </provider> | ||
640 | </entry> | ||
641 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/suite.py"> | ||
642 | <provider selected="true" editor-type-id="text-editor"> | ||
643 | <state relative-caret-position="149"> | ||
644 | <caret line="83" column="0" lean-forward="false" selection-start-line="83" selection-start-column="0" selection-end-line="83" selection-end-column="0" /> | ||
645 | <folding /> | ||
646 | </state> | ||
647 | </provider> | ||
648 | </entry> | ||
649 | <entry file="file://$PROJECT_DIR$/test_suites/test_elecCard.py"> | ||
650 | <provider selected="true" editor-type-id="text-editor"> | ||
651 | <state relative-caret-position="0"> | ||
652 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="1" selection-end-column="23" /> | ||
653 | </state> | ||
654 | </provider> | ||
655 | </entry> | ||
656 | <entry file="file://$PROJECT_DIR$/data_fixture/authCode.py" /> | ||
657 | <entry file="file://$PROJECT_DIR$/test_cases/eleccard_check.py"> | ||
658 | <provider selected="true" editor-type-id="text-editor"> | ||
659 | <state relative-caret-position="136"> | ||
660 | <caret line="8" column="44" lean-forward="true" selection-start-line="8" selection-start-column="44" selection-end-line="8" selection-end-column="44" /> | ||
661 | <folding /> | ||
662 | </state> | ||
663 | </provider> | ||
664 | </entry> | ||
665 | <entry file="file://$PROJECT_DIR$/data_fixture/test_verify.py"> | ||
666 | <provider selected="true" editor-type-id="text-editor"> | ||
667 | <state relative-caret-position="187"> | ||
668 | <caret line="11" column="0" lean-forward="true" selection-start-line="11" selection-start-column="0" selection-end-line="11" selection-end-column="0" /> | ||
669 | </state> | ||
670 | </provider> | ||
671 | </entry> | ||
672 | <entry file="file://$PROJECT_DIR$/test_cases/region_grade_school.py"> | ||
673 | <provider selected="true" editor-type-id="text-editor"> | ||
674 | <state relative-caret-position="340"> | ||
675 | <caret line="20" column="81" lean-forward="true" selection-start-line="8" selection-start-column="0" selection-end-line="20" selection-end-column="81" /> | ||
676 | <folding> | ||
677 | <element signature="e#47#62#0" expanded="false" /> | ||
678 | </folding> | ||
679 | </state> | ||
680 | </provider> | ||
681 | </entry> | ||
682 | <entry file="file://$PROJECT_DIR$/test_cases/252ED989-0B16-4AB7-81C1-974ABCF6CA11.png" /> | ||
683 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymysql/cursors.py"> | ||
684 | <provider selected="true" editor-type-id="text-editor"> | ||
685 | <state relative-caret-position="240"> | ||
686 | <caret line="166" column="0" lean-forward="false" selection-start-line="166" selection-start-column="0" selection-end-line="166" selection-end-column="0" /> | ||
687 | <folding /> | ||
688 | </state> | ||
689 | </provider> | ||
690 | </entry> | ||
691 | <entry file="file://$PROJECT_DIR$/test_cases/eleccard_setUp.py"> | ||
692 | <provider selected="true" editor-type-id="text-editor"> | ||
693 | <state relative-caret-position="209"> | ||
694 | <caret line="102" column="26" lean-forward="true" selection-start-line="102" selection-start-column="26" selection-end-line="102" selection-end-column="26" /> | ||
695 | <folding /> | ||
696 | </state> | ||
697 | </provider> | ||
698 | </entry> | ||
699 | <entry file="file://$APPLICATION_HOME_DIR$/helpers/pydev/pydevd.py"> | ||
700 | <provider selected="true" editor-type-id="text-editor"> | ||
701 | <state relative-caret-position="169"> | ||
702 | <caret line="1595" column="0" lean-forward="false" selection-start-line="1595" selection-start-column="0" selection-end-line="1595" selection-end-column="0" /> | ||
703 | <folding /> | ||
704 | </state> | ||
705 | </provider> | ||
706 | </entry> | ||
707 | <entry file="file://$PROJECT_DIR$/test_cases/press.py"> | ||
708 | <provider selected="true" editor-type-id="text-editor"> | ||
709 | <state relative-caret-position="0"> | ||
710 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="11" selection-end-column="0" /> | ||
711 | <folding /> | ||
712 | </state> | ||
713 | </provider> | ||
714 | </entry> | ||
715 | <entry file="file://$PROJECT_DIR$/test_cases/register.py"> | ||
716 | <provider selected="true" editor-type-id="text-editor"> | ||
717 | <state relative-caret-position="17"> | ||
718 | <caret line="205" column="22" lean-forward="false" selection-start-line="205" selection-start-column="22" selection-end-line="205" selection-end-column="22" /> | ||
719 | <folding> | ||
720 | <element signature="e#47#62#0" expanded="true" /> | ||
721 | </folding> | ||
722 | </state> | ||
723 | </provider> | ||
724 | </entry> | ||
725 | <entry file="file://$PROJECT_DIR$/HTMLTestRunner.py"> | ||
726 | <provider selected="true" editor-type-id="text-editor"> | ||
727 | <state relative-caret-position="165"> | ||
728 | <caret line="643" column="0" lean-forward="false" selection-start-line="643" selection-start-column="0" selection-end-line="643" selection-end-column="0" /> | ||
729 | <folding> | ||
730 | <element signature="e#8852#10678#0" expanded="false" /> | ||
731 | </folding> | ||
732 | </state> | ||
733 | </provider> | ||
734 | </entry> | ||
735 | <entry file="file://$PROJECT_DIR$/test_cases/personal_info.py"> | ||
736 | <provider selected="true" editor-type-id="text-editor"> | ||
737 | <state relative-caret-position="415"> | ||
738 | <caret line="251" column="26" lean-forward="false" selection-start-line="251" selection-start-column="26" selection-end-line="251" selection-end-column="26" /> | ||
739 | <folding> | ||
740 | <element signature="e#47#62#0" expanded="true" /> | ||
741 | </folding> | ||
742 | </state> | ||
743 | </provider> | ||
744 | </entry> | ||
745 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/site-packages/pymysql/connections.py"> | ||
746 | <provider selected="true" editor-type-id="text-editor"> | ||
747 | <state relative-caret-position="176"> | ||
748 | <caret line="1334" column="0" lean-forward="false" selection-start-line="1334" selection-start-column="0" selection-end-line="1334" selection-end-column="0" /> | ||
749 | <folding /> | ||
750 | </state> | ||
751 | </provider> | ||
752 | </entry> | ||
753 | <entry file="file://$PROJECT_DIR$/test_cases/parent_space.py"> | ||
754 | <provider selected="true" editor-type-id="text-editor"> | ||
755 | <state relative-caret-position="713"> | ||
756 | <caret line="105" column="0" lean-forward="false" selection-start-line="105" selection-start-column="0" selection-end-line="105" selection-end-column="0" /> | ||
757 | <folding> | ||
758 | <element signature="e#47#62#0" expanded="true" /> | ||
759 | <marker date="1514955274000" expanded="true" signature="2800:2884" ph="SELECT custo... ozing_customermachine" /> | ||
760 | </folding> | ||
761 | </state> | ||
762 | </provider> | ||
763 | </entry> | ||
764 | <entry file="file://$PROJECT_DIR$/test_cases/sub_account.py"> | ||
765 | <provider selected="true" editor-type-id="text-editor"> | ||
766 | <state relative-caret-position="423"> | ||
767 | <caret line="51" column="41" lean-forward="true" selection-start-line="51" selection-start-column="41" selection-end-line="51" selection-end-column="41" /> | ||
768 | <folding> | ||
769 | <element signature="e#47#62#0" expanded="true" /> | ||
770 | </folding> | ||
771 | </state> | ||
772 | </provider> | ||
773 | </entry> | ||
774 | <entry file="file://$PROJECT_DIR$/report/test_report.html"> | ||
775 | <provider selected="true" editor-type-id="text-editor"> | ||
776 | <state relative-caret-position="0"> | ||
777 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> | ||
778 | <folding /> | ||
779 | </state> | ||
780 | </provider> | ||
781 | </entry> | ||
782 | <entry file="file:///Library/Frameworks/Python.framework/Versions/3.6/lib/python3.6/unittest/case.py"> | ||
783 | <provider selected="true" editor-type-id="text-editor"> | ||
784 | <state relative-caret-position="359"> | ||
785 | <caret line="600" column="0" lean-forward="false" selection-start-line="600" selection-start-column="0" selection-end-line="600" selection-end-column="0" /> | ||
786 | <folding /> | ||
787 | </state> | ||
788 | </provider> | ||
789 | </entry> | ||
790 | <entry file="file://$PROJECT_DIR$/data_fixture/config_data.py"> | ||
791 | <provider selected="true" editor-type-id="text-editor"> | ||
792 | <state relative-caret-position="114"> | ||
793 | <caret line="12" column="14" lean-forward="false" selection-start-line="12" selection-start-column="14" selection-end-line="12" selection-end-column="14" /> | ||
794 | <folding /> | ||
795 | </state> | ||
796 | </provider> | ||
797 | </entry> | ||
798 | <entry file="file://$PROJECT_DIR$/data_fixture/create_testdata.py"> | ||
799 | <provider selected="true" editor-type-id="text-editor"> | ||
800 | <state relative-caret-position="310"> | ||
801 | <caret line="356" column="79" lean-forward="false" selection-start-line="356" selection-start-column="67" selection-end-line="356" selection-end-column="79" /> | ||
802 | <folding> | ||
803 | <element signature="e#47#83#0" expanded="true" /> | ||
804 | <marker date="1515219431000" expanded="true" signature="1421:1488" ph="select * fro... ozing_customermachine" /> | ||
805 | <marker date="1515219431000" expanded="true" signature="1421:1489" ph="select * fro... ozing_customermachine" /> | ||
806 | <marker date="1515219431000" expanded="true" signature="1421:1491" ph="select * fro... ozing_customermachine" /> | ||
807 | <marker date="1515219431000" expanded="true" signature="1421:1492" ph="select * fro... ozing_customermachine" /> | ||
808 | <marker date="1515219431000" expanded="true" signature="1421:1518" ph="select * fro... ozing_customermachine" /> | ||
809 | <marker date="1515219431000" expanded="true" signature="1549:1608" ph="SELECT * FRO... ozing_machine" /> | ||
810 | <marker date="1515219431000" expanded="true" signature="1549:1609" ph="SELECT * FRO... ozing_machine" /> | ||
811 | <marker date="1515219431000" expanded="true" signature="1549:1612" ph="SELECT * FRO... ozing_machine" /> | ||
812 | <marker date="1515219431000" expanded="true" signature="1549:1613" ph="SELECT * FRO... ozing_machine" /> | ||
813 | <marker date="1515219431000" expanded="true" signature="1549:1639" ph="SELECT * FRO... ozing_machine" /> | ||
814 | <marker date="1515219431000" expanded="true" signature="1752:2214" ph="insert into acornuser.ozing_customermachine... " /> | ||
815 | <marker date="1515219431000" expanded="true" signature="2928:2997" ph="SELECT * FRO... ozing_samplemachine" /> | ||
816 | <marker date="1515219431000" expanded="true" signature="3049:3113" ph="SELECT * FRO... ozing_machine" /> | ||
817 | <marker date="1515219431000" expanded="true" signature="4735:4806" ph="select * fro... ozing_customermachine" /> | ||
818 | <marker date="1515219431000" expanded="true" signature="5151:5215" ph="SELECT * FRO... ozing_machine" /> | ||
819 | <marker date="1515219431000" expanded="true" signature="5276:5356" ph="SELECT * FRO... ozing_machine" /> | ||
820 | <marker date="1515219431000" expanded="true" signature="6222:6293" ph="select * fro... ozing_customermachine" /> | ||
821 | <marker date="1515219431000" expanded="true" signature="6578:6641" ph="select * fro... ozing_machine" /> | ||
822 | <marker date="1515219431000" expanded="true" signature="7715:7780" ph="update acorn... " /> | ||
823 | <marker date="1515219431000" expanded="true" signature="7715:7804" ph="update acorn... " /> | ||
824 | <marker date="1515219431000" expanded="true" signature="7928:8009" ph="select * fro... child_user" /> | ||
825 | <marker date="1515219431000" expanded="true" signature="8075:8156" ph="select * fro... child_user" /> | ||
826 | <marker date="1515219431000" expanded="true" signature="8075:8203" ph="select * fro... child_user" /> | ||
827 | <marker date="1515219431000" expanded="true" signature="8075:8205" ph="select * fro... child_user" /> | ||
828 | <marker date="1515219431000" expanded="true" signature="9093:9178" ph="select * fro... acorn_user_status" /> | ||
829 | <marker date="1515219431000" expanded="true" signature="9320:9420" ph="select * fro... acorn_user_status" /> | ||
830 | <marker date="1515219431000" expanded="true" signature="10158:10258" ph="select * fro... acorn_user_status" /> | ||
831 | <marker date="1515219431000" expanded="true" signature="11302:11360" ph="select * fro... acorn_user_extra" /> | ||
832 | <marker date="1515219431000" expanded="true" signature="11397:11483" ph="select * fro... acorn_user_extra" /> | ||
833 | <marker date="1515219431000" expanded="true" signature="11914:11983" ph="select * fro... subAccount_user_extra" /> | ||
834 | <marker date="1515219431000" expanded="true" signature="11914:11984" ph="select * fro... subAccount_user_extra" /> | ||
835 | <marker date="1515219431000" expanded="true" signature="11914:11988" ph="select * fro... subAccount_user_extra" /> | ||
836 | <marker date="1515219431000" expanded="true" signature="12023:12092" ph="select * fro... subAccount_user_extra" /> | ||
837 | <marker date="1515219431000" expanded="true" signature="12023:12122" ph="select * fro... subAccount_user_extra" /> | ||
838 | <marker date="1515219431000" expanded="true" signature="12023:12138" ph="select * fro... subAccount_user_extra" /> | ||
839 | <marker date="1515219431000" expanded="true" signature="13348:13448" ph="select * fro... ozing_student" /> | ||
840 | <marker date="1515219431000" expanded="true" signature="13550:13636" ph="update acorn... " /> | ||
841 | <marker date="1515219431000" expanded="true" signature="13550:13638" ph="update acorn... " /> | ||
842 | <marker date="1515219431000" expanded="true" signature="13726:13834" ph="select * fro... ozing_student" /> | ||
843 | <marker date="1515219431000" expanded="true" signature="15966:16006" ph="select max(i... acorn_user" /> | ||
844 | <marker date="1515219431000" expanded="true" signature="15966:16008" ph="select max(i... acorn_user" /> | ||
845 | <marker date="1515219431000" expanded="true" signature="16721:16796" ph="select passw... parents_space_pass" /> | ||
846 | <marker date="1515219431000" expanded="true" signature="17752:17804" ph="update analy... " /> | ||
847 | <marker date="1515219431000" expanded="true" signature="17752:17821" ph="update analy... " /> | ||
848 | <marker date="1515219431000" expanded="true" signature="17752:17849" ph="update analy... " /> | ||
849 | <marker date="1515219431000" expanded="true" signature="17752:17850" ph="update analy... " /> | ||
850 | </folding> | ||
851 | </state> | ||
852 | </provider> | ||
853 | </entry> | ||
854 | <entry file="file://$PROJECT_DIR$/test_cases/debugggggg.py"> | ||
855 | <provider selected="true" editor-type-id="text-editor"> | ||
856 | <state relative-caret-position="34"> | ||
857 | <caret line="2" column="0" lean-forward="false" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" /> | ||
858 | <folding /> | ||
859 | </state> | ||
860 | </provider> | ||
861 | </entry> | ||
862 | <entry file="file://$PROJECT_DIR$/test_cases/app_record_statistic.py"> | ||
863 | <provider selected="true" editor-type-id="text-editor"> | ||
864 | <state relative-caret-position="761"> | ||
865 | <caret line="170" column="45" lean-forward="false" selection-start-line="170" selection-start-column="45" selection-end-line="170" selection-end-column="45" /> | ||
866 | <folding> | ||
867 | <element signature="e#47#62#0" expanded="true" /> | ||
868 | </folding> | ||
869 | </state> | ||
870 | </provider> | ||
871 | </entry> | ||
872 | <entry file="file://$PROJECT_DIR$/test_cases/__init__.py"> | ||
873 | <provider selected="true" editor-type-id="text-editor"> | ||
874 | <state relative-caret-position="0"> | ||
875 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> | ||
876 | <folding /> | ||
877 | </state> | ||
878 | </provider> | ||
879 | </entry> | ||
880 | <entry file="file://$PROJECT_DIR$/data_fixture/__init__.py"> | ||
881 | <provider selected="true" editor-type-id="text-editor"> | ||
882 | <state relative-caret-position="0"> | ||
883 | <caret line="0" column="0" lean-forward="false" selection-start-line="0" selection-start-column="0" selection-end-line="0" selection-end-column="0" /> | ||
884 | <folding /> | ||
885 | </state> | ||
886 | </provider> | ||
887 | </entry> | ||
888 | <entry file="file://$PROJECT_DIR$/data_fixture/mysql_db.py"> | ||
889 | <provider selected="true" editor-type-id="text-editor"> | ||
890 | <state relative-caret-position="34"> | ||
891 | <caret line="2" column="0" lean-forward="true" selection-start-line="2" selection-start-column="0" selection-end-line="2" selection-end-column="0" /> | ||
892 | <folding> | ||
893 | <marker date="1514616463000" expanded="true" signature="1672:1692" ph="select * fro... " /> | ||
894 | <marker date="1514616463000" expanded="true" signature="1672:1694" ph="select * fro... missing_value" /> | ||
895 | <marker date="1514616463000" expanded="true" signature="1672:1718" ph="select count... missing_value" /> | ||
896 | <marker date="1514616463000" expanded="true" signature="1672:1719" ph="select count... missing_value" /> | ||
897 | </folding> | ||
898 | </state> | ||
899 | </provider> | ||
900 | </entry> | ||
901 | <entry file="file://$PROJECT_DIR$/test_cases/subject_sync.py"> | ||
902 | <provider selected="true" editor-type-id="text-editor"> | ||
903 | <state relative-caret-position="85"> | ||
904 | <caret line="5" column="66" lean-forward="true" selection-start-line="5" selection-start-column="66" selection-end-line="5" selection-end-column="66" /> | ||
905 | <folding /> | ||
906 | </state> | ||
907 | </provider> | ||
908 | </entry> | ||
909 | <entry file="file://$PROJECT_DIR$/run_test.py"> | ||
910 | <provider selected="true" editor-type-id="text-editor"> | ||
911 | <state relative-caret-position="289"> | ||
912 | <caret line="17" column="0" lean-forward="true" selection-start-line="17" selection-start-column="0" selection-end-line="17" selection-end-column="0" /> | ||
913 | <folding> | ||
914 | <element signature="e#47#62#0" expanded="true" /> | ||
915 | </folding> | ||
916 | </state> | ||
917 | </provider> | ||
918 | </entry> | ||
919 | </component> | ||
920 | </project> |
HTMLTestRunner.py
File was created | 1 | # -*- coding: utf-8 -*- | |
2 | |||
3 | """ | ||
4 | A TestRunner for use with the Python unit testing framework. It | ||
5 | generates a HTML report to show the result at a glance. | ||
6 | |||
7 | The simplest way to use this is to invoke its main method. E.g. | ||
8 | |||
9 | import unittest | ||
10 | import HTMLTestRunner | ||
11 | |||
12 | ... define your tests ... | ||
13 | |||
14 | if __name__ == '__main__': | ||
15 | HTMLTestRunner.main() | ||
16 | |||
17 | |||
18 | For more customization options, instantiates a HTMLTestRunner object. | ||
19 | HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. | ||
20 | |||
21 | # output to a file | ||
22 | fp = file('my_report.html', 'wb') | ||
23 | runner = HTMLTestRunner.HTMLTestRunner( | ||
24 | stream=fp, | ||
25 | title='My unit test', | ||
26 | description='This demonstrates the report output by HTMLTestRunner.' | ||
27 | ) | ||
28 | |||
29 | # Use an external stylesheet. | ||
30 | # See the Template_mixin class for more customizable options | ||
31 | runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">' | ||
32 | |||
33 | # run the test | ||
34 | runner.run(my_test_suite) | ||
35 | |||
36 | |||
37 | ------------------------------------------------------------------------ | ||
38 | Copyright (c) 2004-2007, Wai Yip Tung | ||
39 | All rights reserved. | ||
40 | |||
41 | Redistribution and use in source and binary forms, with or without | ||
42 | modification, are permitted provided that the following conditions are | ||
43 | met: | ||
44 | |||
45 | * Redistributions of source code must retain the above copyright notice, | ||
46 | this list of conditions and the following disclaimer. | ||
47 | * Redistributions in binary form must reproduce the above copyright | ||
48 | notice, this list of conditions and the following disclaimer in the | ||
49 | documentation and/or other materials provided with the distribution. | ||
50 | * Neither the name Wai Yip Tung nor the names of its contributors may be | ||
51 | used to endorse or promote products derived from this software without | ||
52 | specific prior written permission. | ||
53 | |||
54 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
55 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
56 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
57 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
58 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
59 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
60 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
61 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
62 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
63 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
64 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
65 | """ | ||
66 | |||
67 | # URL: http://tungwaiyip.info/software/HTMLTestRunner.html | ||
68 | |||
69 | __author__ = "Wai Yip Tung" | ||
70 | __version__ = "0.8.2" | ||
71 | |||
72 | |||
73 | """ | ||
74 | Change History | ||
75 | |||
76 | Version 0.8.2 | ||
77 | * Show output inline instead of popup window (Viorel Lupu). | ||
78 | |||
79 | Version in 0.8.1 | ||
80 | * Validated XHTML (Wolfgang Borgert). | ||
81 | * Added description of test classes and test cases. | ||
82 | |||
83 | Version in 0.8.0 | ||
84 | * Define Template_mixin class for customization. | ||
85 | * Workaround a IE 6 bug that it does not treat <script> block as CDATA. | ||
86 | |||
87 | Version in 0.7.1 | ||
88 | * Back port to Python 2.3 (Frank Horowitz). | ||
89 | * Fix missing scroll bars in detail log (Podi). | ||
90 | """ | ||
91 | |||
92 | # TODO: color stderr | ||
93 | # TODO: simplify javascript using ,ore than 1 class in the class attribute? | ||
94 | |||
95 | import datetime | ||
96 | import io | ||
97 | import sys | ||
98 | import time | ||
99 | import unittest | ||
100 | from xml.sax import saxutils | ||
101 | |||
102 | |||
103 | # ------------------------------------------------------------------------ | ||
104 | # The redirectors below are used to capture output during testing. Output | ||
105 | # sent to sys.stdout and sys.stderr are automatically captured. However | ||
106 | # in some cases sys.stdout is already cached before HTMLTestRunner is | ||
107 | # invoked (e.g. calling logging.basicConfig). In order to capture those | ||
108 | # output, use the redirectors for the cached stream. | ||
109 | # | ||
110 | # e.g. | ||
111 | # >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector) | ||
112 | # >>> | ||
113 | |||
114 | class OutputRedirector(object): | ||
115 | """ Wrapper to redirect stdout or stderr """ | ||
116 | def __init__(self, fp): | ||
117 | self.fp = fp | ||
118 | |||
119 | def write(self, s): | ||
120 | self.fp.write(s) | ||
121 | |||
122 | def writelines(self, lines): | ||
123 | self.fp.writelines(lines) | ||
124 | |||
125 | def flush(self): | ||
126 | self.fp.flush() | ||
127 | |||
128 | stdout_redirector = OutputRedirector(sys.stdout) | ||
129 | stderr_redirector = OutputRedirector(sys.stderr) | ||
130 | |||
131 | |||
132 | |||
133 | # ---------------------------------------------------------------------- | ||
134 | # Template | ||
135 | |||
136 | class Template_mixin(object): | ||
137 | """ | ||
138 | Define a HTML template for report customerization and generation. | ||
139 | |||
140 | Overall structure of an HTML report | ||
141 | |||
142 | HTML | ||
143 | +------------------------+ | ||
144 | |<html> | | ||
145 | | <head> | | ||
146 | | | | ||
147 | | STYLESHEET | | ||
148 | | +----------------+ | | ||
149 | | | | | | ||
150 | | +----------------+ | | ||
151 | | | | ||
152 | | </head> | | ||
153 | | | | ||
154 | | <body> | | ||
155 | | | | ||
156 | | HEADING | | ||
157 | | +----------------+ | | ||
158 | | | | | | ||
159 | | +----------------+ | | ||
160 | | | | ||
161 | | REPORT | | ||
162 | | +----------------+ | | ||
163 | | | | | | ||
164 | | +----------------+ | | ||
165 | | | | ||
166 | | ENDING | | ||
167 | | +----------------+ | | ||
168 | | | | | | ||
169 | | +----------------+ | | ||
170 | | | | ||
171 | | </body> | | ||
172 | |</html> | | ||
173 | +------------------------+ | ||
174 | """ | ||
175 | |||
176 | STATUS = { | ||
177 | 0: 'pass', | ||
178 | 1: 'fail', | ||
179 | 2: 'error', | ||
180 | } | ||
181 | |||
182 | DEFAULT_TITLE = 'Unit Test Report' | ||
183 | DEFAULT_DESCRIPTION = '' | ||
184 | |||
185 | # ------------------------------------------------------------------------ | ||
186 | # HTML Template | ||
187 | |||
188 | HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?> | ||
189 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
190 | <html xmlns="http://www.w3.org/1999/xhtml"> | ||
191 | <head> | ||
192 | <title>%(title)s</title> | ||
193 | <meta name="generator" content="%(generator)s"/> | ||
194 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||
195 | %(stylesheet)s | ||
196 | </head> | ||
197 | <body> | ||
198 | <script language="javascript" type="text/javascript"><!-- | ||
199 | output_list = Array(); | ||
200 | |||
201 | /* level - 0:Summary; 1:Failed; 2:All */ | ||
202 | function showCase(level) { | ||
203 | trs = document.getElementsByTagName("tr"); | ||
204 | for (var i = 0; i < trs.length; i++) { | ||
205 | tr = trs[i]; | ||
206 | id = tr.id; | ||
207 | if (id.substr(0,2) == 'ft') { | ||
208 | if (level < 1) { | ||
209 | tr.className = 'hiddenRow'; | ||
210 | } | ||
211 | else { | ||
212 | tr.className = ''; | ||
213 | } | ||
214 | } | ||
215 | if (id.substr(0,2) == 'pt') { | ||
216 | if (level > 1) { | ||
217 | tr.className = ''; | ||
218 | } | ||
219 | else { | ||
220 | tr.className = 'hiddenRow'; | ||
221 | } | ||
222 | } | ||
223 | } | ||
224 | } | ||
225 | |||
226 | |||
227 | function showClassDetail(cid, count) { | ||
228 | var id_list = Array(count); | ||
229 | var toHide = 1; | ||
230 | for (var i = 0; i < count; i++) { | ||
231 | tid0 = 't' + cid.substr(1) + '.' + (i+1); | ||
232 | tid = 'f' + tid0; | ||
233 | tr = document.getElementById(tid); | ||
234 | if (!tr) { | ||
235 | tid = 'p' + tid0; | ||
236 | tr = document.getElementById(tid); | ||
237 | } | ||
238 | id_list[i] = tid; | ||
239 | if (tr.className) { | ||
240 | toHide = 0; | ||
241 | } | ||
242 | } | ||
243 | for (var i = 0; i < count; i++) { | ||
244 | tid = id_list[i]; | ||
245 | if (toHide) { | ||
246 | document.getElementById('div_'+tid).style.display = 'none' | ||
247 | document.getElementById(tid).className = 'hiddenRow'; | ||
248 | } | ||
249 | else { | ||
250 | document.getElementById(tid).className = ''; | ||
251 | } | ||
252 | } | ||
253 | } | ||
254 | |||
255 | |||
256 | function showTestDetail(div_id){ | ||
257 | var details_div = document.getElementById(div_id) | ||
258 | var displayState = details_div.style.display | ||
259 | // alert(displayState) | ||
260 | if (displayState != 'block' ) { | ||
261 | displayState = 'block' | ||
262 | details_div.style.display = 'block' | ||
263 | } | ||
264 | else { | ||
265 | details_div.style.display = 'none' | ||
266 | } | ||
267 | } | ||
268 | |||
269 | |||
270 | function html_escape(s) { | ||
271 | s = s.replace(/&/g,'&'); | ||
272 | s = s.replace(/</g,'<'); | ||
273 | s = s.replace(/>/g,'>'); | ||
274 | return s; | ||
275 | } | ||
276 | |||
277 | /* obsoleted by detail in <div> | ||
278 | function showOutput(id, name) { | ||
279 | var w = window.open("", //url | ||
280 | name, | ||
281 | "resizable,scrollbars,status,width=800,height=450"); | ||
282 | d = w.document; | ||
283 | d.write("<pre>"); | ||
284 | d.write(html_escape(output_list[id])); | ||
285 | d.write("\n"); | ||
286 | d.write("<a href='javascript:window.close()'>close</a>\n"); | ||
287 | d.write("</pre>\n"); | ||
288 | d.close(); | ||
289 | } | ||
290 | */ | ||
291 | --></script> | ||
292 | |||
293 | %(heading)s | ||
294 | %(report)s | ||
295 | %(ending)s | ||
296 | |||
297 | </body> | ||
298 | </html> | ||
299 | """ | ||
300 | # variables: (title, generator, stylesheet, heading, report, ending) | ||
301 | |||
302 | |||
303 | # ------------------------------------------------------------------------ | ||
304 | # Stylesheet | ||
305 | # | ||
306 | # alternatively use a <link> for external style sheet, e.g. | ||
307 | # <link rel="stylesheet" href="$url" type="text/css"> | ||
308 | |||
309 | STYLESHEET_TMPL = """ | ||
310 | <style type="text/css" media="screen"> | ||
311 | body { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; } | ||
312 | table { font-size: 100%; } | ||
313 | pre { } | ||
314 | |||
315 | /* -- heading ---------------------------------------------------------------------- */ | ||
316 | h1 { | ||
317 | font-size: 16pt; | ||
318 | color: gray; | ||
319 | } | ||
320 | .heading { | ||
321 | margin-top: 0ex; | ||
322 | margin-bottom: 1ex; | ||
323 | } | ||
324 | |||
325 | .heading .attribute { | ||
326 | margin-top: 1ex; | ||
327 | margin-bottom: 0; | ||
328 | } | ||
329 | |||
330 | .heading .description { | ||
331 | margin-top: 4ex; | ||
332 | margin-bottom: 6ex; | ||
333 | } | ||
334 | |||
335 | /* -- css div popup ------------------------------------------------------------------------ */ | ||
336 | a.popup_link { | ||
337 | } | ||
338 | |||
339 | a.popup_link:hover { | ||
340 | color: red; | ||
341 | } | ||
342 | |||
343 | .popup_window { | ||
344 | display: none; | ||
345 | position: relative; | ||
346 | left: 0px; | ||
347 | top: 0px; | ||
348 | /*border: solid #627173 1px; */ | ||
349 | padding: 10px; | ||
350 | background-color: #E6E6D6; | ||
351 | font-family: "Lucida Console", "Courier New", Courier, monospace; | ||
352 | text-align: left; | ||
353 | font-size: 8pt; | ||
354 | width: 500px; | ||
355 | } | ||
356 | |||
357 | } | ||
358 | /* -- report ------------------------------------------------------------------------ */ | ||
359 | #show_detail_line { | ||
360 | margin-top: 3ex; | ||
361 | margin-bottom: 1ex; | ||
362 | } | ||
363 | #result_table { | ||
364 | width: 80%; | ||
365 | border-collapse: collapse; | ||
366 | border: 1px solid #777; | ||
367 | } | ||
368 | #header_row { | ||
369 | font-weight: bold; | ||
370 | color: white; | ||
371 | background-color: #777; | ||
372 | } | ||
373 | #result_table td { | ||
374 | border: 1px solid #777; | ||
375 | padding: 2px; | ||
376 | } | ||
377 | #total_row { font-weight: bold; } | ||
378 | .passClass { background-color: #6c6; } | ||
379 | .failClass { background-color: #c60; } | ||
380 | .errorClass { background-color: #c00; } | ||
381 | .passCase { color: #6c6; } | ||
382 | .failCase { color: #c60; font-weight: bold; } | ||
383 | .errorCase { color: #c00; font-weight: bold; } | ||
384 | .hiddenRow { display: none; } | ||
385 | .testcase { margin-left: 2em; } | ||
386 | |||
387 | |||
388 | /* -- ending ---------------------------------------------------------------------- */ | ||
389 | #ending { | ||
390 | } | ||
391 | |||
392 | </style> | ||
393 | """ | ||
394 | |||
395 | |||
396 | |||
397 | # ------------------------------------------------------------------------ | ||
398 | # Heading | ||
399 | # | ||
400 | |||
401 | HEADING_TMPL = """<div class='heading'> | ||
402 | <h1>%(title)s</h1> | ||
403 | %(parameters)s | ||
404 | <p class='description'>%(description)s</p> | ||
405 | </div> | ||
406 | |||
407 | """ # variables: (title, parameters, description) | ||
408 | |||
409 | HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p> | ||
410 | """ # variables: (name, value) | ||
411 | |||
412 | |||
413 | |||
414 | # ------------------------------------------------------------------------ | ||
415 | # Report | ||
416 | # | ||
417 | |||
418 | REPORT_TMPL = """ | ||
419 | <p id='show_detail_line'>Show | ||
420 | <a href='javascript:showCase(0)'>Summary</a> | ||
421 | <a href='javascript:showCase(1)'>Failed</a> | ||
422 | <a href='javascript:showCase(2)'>All</a> | ||
423 | </p> | ||
424 | <table id='result_table'> | ||
425 | <colgroup> | ||
426 | <col align='left' /> | ||
427 | <col align='right' /> | ||
428 | <col align='right' /> | ||
429 | <col align='right' /> | ||
430 | <col align='right' /> | ||
431 | <col align='right' /> | ||
432 | </colgroup> | ||
433 | <tr id='header_row'> | ||
434 | <td>Test Group/Test case</td> | ||
435 | <td>Count</td> | ||
436 | <td>Pass</td> | ||
437 | <td>Fail</td> | ||
438 | <td>Error</td> | ||
439 | <td>View</td> | ||
440 | </tr> | ||
441 | %(test_list)s | ||
442 | <tr id='total_row'> | ||
443 | <td>Total</td> | ||
444 | <td>%(count)s</td> | ||
445 | <td>%(Pass)s</td> | ||
446 | <td>%(fail)s</td> | ||
447 | <td>%(error)s</td> | ||
448 | <td> </td> | ||
449 | </tr> | ||
450 | </table> | ||
451 | """ # variables: (test_list, count, Pass, fail, error) | ||
452 | |||
453 | REPORT_CLASS_TMPL = r""" | ||
454 | <tr class='%(style)s'> | ||
455 | <td>%(desc)s</td> | ||
456 | <td>%(count)s</td> | ||
457 | <td>%(Pass)s</td> | ||
458 | <td>%(fail)s</td> | ||
459 | <td>%(error)s</td> | ||
460 | <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td> | ||
461 | </tr> | ||
462 | """ # variables: (style, desc, count, Pass, fail, error, cid) | ||
463 | |||
464 | |||
465 | REPORT_TEST_WITH_OUTPUT_TMPL = r""" | ||
466 | <tr id='%(tid)s' class='%(Class)s'> | ||
467 | <td class='%(style)s'><div class='testcase'>%(desc)s</div></td> | ||
468 | <td colspan='5' align='center'> | ||
469 | |||
470 | <!--css div popup start--> | ||
471 | <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" > | ||
472 | %(status)s</a> | ||
473 | |||
474 | <div id='div_%(tid)s' class="popup_window"> | ||
475 | <div style='text-align: right; color:red;cursor:pointer'> | ||
476 | <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " > | ||
477 | [x]</a> | ||
478 | </div> | ||
479 | <pre> | ||
480 | %(script)s | ||
481 | </pre> | ||
482 | </div> | ||
483 | <!--css div popup end--> | ||
484 | |||
485 | </td> | ||
486 | </tr> | ||
487 | """ # variables: (tid, Class, style, desc, status) | ||
488 | |||
489 | |||
490 | REPORT_TEST_NO_OUTPUT_TMPL = r""" | ||
491 | <tr id='%(tid)s' class='%(Class)s'> | ||
492 | <td class='%(style)s'><div class='testcase'>%(desc)s</div></td> | ||
493 | <td colspan='5' align='center'>%(status)s</td> | ||
494 | </tr> | ||
495 | """ # variables: (tid, Class, style, desc, status) | ||
496 | |||
497 | |||
498 | REPORT_TEST_OUTPUT_TMPL = r""" | ||
499 | %(id)s: %(output)s | ||
500 | """ # variables: (id, output) | ||
501 | |||
502 | |||
503 | |||
504 | # ------------------------------------------------------------------------ | ||
505 | # ENDING | ||
506 | # | ||
507 | |||
508 | ENDING_TMPL = """<div id='ending'> </div>""" | ||
509 | |||
510 | # -------------------- The end of the Template class ------------------- | ||
511 | |||
512 | |||
513 | TestResult = unittest.TestResult | ||
514 | |||
515 | class _TestResult(TestResult): | ||
516 | # note: _TestResult is a pure representation of results. | ||
517 | # It lacks the output and reporting ability compares to unittest._TextTestResult. | ||
518 | |||
519 | def __init__(self, verbosity=1): | ||
520 | TestResult.__init__(self) | ||
521 | self.stdout0 = None | ||
522 | self.stderr0 = None | ||
523 | self.success_count = 0 | ||
524 | self.failure_count = 0 | ||
525 | self.error_count = 0 | ||
526 | self.verbosity = verbosity | ||
527 | |||
528 | # result is a list of result in 4 tuple | ||
529 | # ( | ||
530 | # result code (0: success; 1: fail; 2: error), | ||
531 | # TestCase object, | ||
532 | # Test output (byte string), | ||
533 | # stack trace, | ||
534 | # ) | ||
535 | self.result = [] | ||
536 | |||
537 | |||
538 | def startTest(self, test): | ||
539 | TestResult.startTest(self, test) | ||
540 | # just one buffer for both stdout and stderr | ||
541 | self.outputBuffer = io.StringIO() | ||
542 | stdout_redirector.fp = self.outputBuffer | ||
543 | stderr_redirector.fp = self.outputBuffer | ||
544 | self.stdout0 = sys.stdout | ||
545 | self.stderr0 = sys.stderr | ||
546 | sys.stdout = stdout_redirector | ||
547 | sys.stderr = stderr_redirector | ||
548 | |||
549 | |||
550 | def complete_output(self): | ||
551 | """ | ||
552 | Disconnect output redirection and return buffer. | ||
553 | Safe to call multiple times. | ||
554 | """ | ||
555 | if self.stdout0: | ||
556 | sys.stdout = self.stdout0 | ||
557 | sys.stderr = self.stderr0 | ||
558 | self.stdout0 = None | ||
559 | self.stderr0 = None | ||
560 | return self.outputBuffer.getvalue() | ||
561 | |||
562 | |||
563 | def stopTest(self, test): | ||
564 | # Usually one of addSuccess, addError or addFailure would have been called. | ||
565 | # But there are some path in unittest that would bypass this. | ||
566 | # We must disconnect stdout in stopTest(), which is guaranteed to be called. | ||
567 | self.complete_output() | ||
568 | |||
569 | |||
570 | def addSuccess(self, test): | ||
571 | self.success_count += 1 | ||
572 | TestResult.addSuccess(self, test) | ||
573 | output = self.complete_output() | ||
574 | self.result.append((0, test, output, '')) | ||
575 | if self.verbosity > 1: | ||
576 | sys.stderr.write('ok ') | ||
577 | sys.stderr.write(str(test)) | ||
578 | sys.stderr.write('\n') | ||
579 | else: | ||
580 | sys.stderr.write('.') | ||
581 | |||
582 | def addError(self, test, err): | ||
583 | self.error_count += 1 | ||
584 | TestResult.addError(self, test, err) | ||
585 | _, _exc_str = self.errors[-1] | ||
586 | output = self.complete_output() | ||
587 | self.result.append((2, test, output, _exc_str)) | ||
588 | if self.verbosity > 1: | ||
589 | sys.stderr.write('E ') | ||
590 | sys.stderr.write(str(test)) | ||
591 | sys.stderr.write('\n') | ||
592 | else: | ||
593 | sys.stderr.write('E') | ||
594 | |||
595 | def addFailure(self, test, err): | ||
596 | self.failure_count += 1 | ||
597 | TestResult.addFailure(self, test, err) | ||
598 | _, _exc_str = self.failures[-1] | ||
599 | output = self.complete_output() | ||
600 | self.result.append((1, test, output, _exc_str)) | ||
601 | if self.verbosity > 1: | ||
602 | sys.stderr.write('F ') | ||
603 | sys.stderr.write(str(test)) | ||
604 | sys.stderr.write('\n') | ||
605 | else: | ||
606 | sys.stderr.write('F') | ||
607 | |||
608 | |||
609 | class HTMLTestRunner(Template_mixin): | ||
610 | """ | ||
611 | """ | ||
612 | #def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None): | ||
613 | def __init__(self, outputdir, verbosity=1, title=None, description=None, report_name='test_report.html'): | ||
614 | #self.stream = self._create_output_file(outputdir, report_name) | ||
615 | self.outputdir = outputdir | ||
616 | self.report_name = report_name | ||
617 | self.verbosity = verbosity | ||
618 | if title is None: | ||
619 | self.title = self.DEFAULT_TITLE | ||
620 | else: | ||
621 | self.title = title | ||
622 | if description is None: | ||
623 | self.description = self.DEFAULT_DESCRIPTION | ||
624 | else: | ||
625 | self.description = description | ||
626 | |||
627 | self.startTime = datetime.datetime.now() | ||
628 | |||
629 | |||
630 | def _create_output_file(self, output, report_name): | ||
631 | import os | ||
632 | """ Generate the report file in the given path. """ | ||
633 | current_dir = os.getcwd() | ||
634 | dir_to = os.path.join(current_dir, output) | ||
635 | if not os.path.exists(dir_to): | ||
636 | os.makedirs(dir_to) | ||
637 | path_file = os.path.join(dir_to, report_name) | ||
638 | return path_file | ||
639 | |||
640 | |||
641 | def run(self, test): | ||
642 | "Run the given test case or test suite." | ||
643 | result = _TestResult(self.verbosity) | ||
644 | test(result) | ||
645 | self.stopTime = datetime.datetime.now() | ||
646 | self.generateReport(test, result) | ||
647 | # print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime) | ||
648 | print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)) | ||
649 | return result | ||
650 | |||
651 | |||
652 | def sortResult(self, result_list): | ||
653 | # unittest does not seems to run in any particular order. | ||
654 | # Here at least we want to group them together by class. | ||
655 | rmap = {} | ||
656 | classes = [] | ||
657 | for n,t,o,e in result_list: | ||
658 | cls = t.__class__ | ||
659 | if not cls in rmap: | ||
660 | rmap[cls] = [] | ||
661 | classes.append(cls) | ||
662 | rmap[cls].append((n,t,o,e)) | ||
663 | r = [(cls, rmap[cls]) for cls in classes] | ||
664 | return r | ||
665 | |||
666 | |||
667 | def getReportAttributes(self, result): | ||
668 | """ | ||
669 | Return report attributes as a list of (name, value). | ||
670 | Override this to add custom attributes. | ||
671 | """ | ||
672 | startTime = str(self.startTime)[:19] | ||
673 | duration = str(self.stopTime - self.startTime) | ||
674 | status = [] | ||
675 | if result.success_count: status.append('Pass %s' % result.success_count) | ||
676 | if result.failure_count: status.append('Failure %s' % result.failure_count) | ||
677 | if result.error_count: status.append('Error %s' % result.error_count ) | ||
678 | if status: | ||
679 | status = ' '.join(status) | ||
680 | else: | ||
681 | status = 'none' | ||
682 | return [ | ||
683 | ('Start Time', startTime), | ||
684 | ('Duration', duration), | ||
685 | ('Status', status), | ||
686 | ] | ||
687 | |||
688 | |||
689 | |||
690 | def _generate_stylesheet(self): | ||
691 | return self.STYLESHEET_TMPL | ||
692 | |||
693 | |||
694 | def _generate_heading(self, report_attrs): | ||
695 | a_lines = [] | ||
696 | for name, value in report_attrs: | ||
697 | line = self.HEADING_ATTRIBUTE_TMPL % dict( | ||
698 | name = saxutils.escape(name), | ||
699 | value = saxutils.escape(value), | ||
700 | ) | ||
701 | a_lines.append(line) | ||
702 | heading = self.HEADING_TMPL % dict( | ||
703 | title = saxutils.escape(self.title), | ||
704 | parameters = ''.join(a_lines), | ||
705 | description = saxutils.escape(self.description), | ||
706 | ) | ||
707 | return heading | ||
708 | |||
709 | |||
710 | def _generate_report(self, result): | ||
711 | rows = [] | ||
712 | sortedResult = self.sortResult(result.result) | ||
713 | for cid, (cls, cls_results) in enumerate(sortedResult): | ||
714 | # subtotal for a class | ||
715 | np = nf = ne = 0 | ||
716 | for n,t,o,e in cls_results: | ||
717 | if n == 0: np += 1 | ||
718 | elif n == 1: nf += 1 | ||
719 | else: ne += 1 | ||
720 | |||
721 | # format class description | ||
722 | if cls.__module__ == "__main__": | ||
723 | name = cls.__name__ | ||
724 | else: | ||
725 | name = "%s.%s" % (cls.__module__, cls.__name__) | ||
726 | doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" | ||
727 | desc = doc and '%s: %s' % (name, doc) or name | ||
728 | |||
729 | row = self.REPORT_CLASS_TMPL % dict( | ||
730 | style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', | ||
731 | desc = desc, | ||
732 | count = np+nf+ne, | ||
733 | Pass = np, | ||
734 | fail = nf, | ||
735 | error = ne, | ||
736 | cid = 'c%s' % (cid+1), | ||
737 | ) | ||
738 | rows.append(row) | ||
739 | |||
740 | for tid, (n,t,o,e) in enumerate(cls_results): | ||
741 | self._generate_report_test(rows, cid, tid, n, t, o, e) | ||
742 | |||
743 | report = self.REPORT_TMPL % dict( | ||
744 | test_list = ''.join(rows), | ||
745 | count = str(result.success_count+result.failure_count+result.error_count), | ||
746 | Pass = str(result.success_count), | ||
747 | fail = str(result.failure_count), | ||
748 | error = str(result.error_count), | ||
749 | ) | ||
750 | return report | ||
751 | |||
752 | |||
753 | def _generate_report_test(self, rows, cid, tid, n, t, o, e): | ||
754 | # e.g. 'pt1.1', 'ft1.1', etc | ||
755 | has_output = bool(o or e) | ||
756 | tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1) | ||
757 | name = t.id().split('.')[-1] | ||
758 | doc = t.shortDescription() or "" | ||
759 | desc = doc and ('%s: %s' % (name, doc)) or name | ||
760 | tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL | ||
761 | |||
762 | # o and e should be byte string because they are collected from stdout and stderr? | ||
763 | if isinstance(o,str): | ||
764 | # TODO: some problem with 'string_escape': it escape \n and mess up formating | ||
765 | # uo = unicode(o.encode('string_escape')) | ||
766 | # uo = o.decode('latin-1') | ||
767 | uo = e | ||
768 | else: | ||
769 | uo = o | ||
770 | if isinstance(e,str): | ||
771 | # TODO: some problem with 'string_escape': it escape \n and mess up formating | ||
772 | # ue = unicode(e.encode('string_escape')) | ||
773 | # ue = e.decode('latin-1') | ||
774 | ue = e | ||
775 | else: | ||
776 | ue = e | ||
777 | |||
778 | script = self.REPORT_TEST_OUTPUT_TMPL % dict( | ||
779 | id = tid, | ||
780 | output = saxutils.escape(str(uo)+ue), | ||
781 | ) | ||
782 | |||
783 | row = tmpl % dict( | ||
784 | tid = tid, | ||
785 | Class = (n == 0 and 'hiddenRow' or 'none'), | ||
786 | style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'), | ||
787 | desc = desc, | ||
788 | script = script, | ||
789 | status = self.STATUS[n], | ||
790 | ) | ||
791 | rows.append(row) | ||
792 | if not has_output: | ||
793 | return | ||
794 | |||
795 | def _generate_ending(self): | ||
796 | return self.ENDING_TMPL | ||
797 | |||
798 | |||
799 | def generateReport(self, test, result): | ||
800 | report_attrs = self.getReportAttributes(result) | ||
801 | generator = 'HTMLTestRunner %s' % __version__ | ||
802 | stylesheet = self._generate_stylesheet() | ||
803 | heading = self._generate_heading(report_attrs) | ||
804 | report = self._generate_report(result) | ||
805 | ending = self._generate_ending() | ||
806 | # output = self.HTML_TMPL % dict( | ||
807 | # title = saxutils.escape(self.title), | ||
808 | # generator = generator, | ||
809 | # stylesheet = stylesheet, | ||
810 | # heading = heading, | ||
811 | # report = report, | ||
812 | # ending = ending, | ||
813 | # ) | ||
814 | |||
815 | output = self.HTML_TMPL % dict( | ||
816 | title=saxutils.escape(self.title), | ||
817 | generator=generator, | ||
818 | stylesheet=stylesheet, | ||
819 | heading=heading, | ||
820 | report=report, | ||
821 | ending=ending, | ||
822 | ) | ||
823 | |||
824 | path_file = self._create_output_file(self.outputdir, self.report_name) | ||
825 | with open(path_file, 'wb') as report_file: | ||
826 | report_file.write(output.encode('utf-8')) | ||
827 | #report_file.write(output) | ||
828 | |||
829 | |||
830 | ############################################################################## | ||
831 | # Facilities for running tests from the command line | ||
832 | ############################################################################## | ||
833 | |||
834 | # Note: Reuse unittest.TestProgram to launch test. In the future we may | ||
835 | # build our own launcher to support more specific command line | ||
836 | # parameters like test title, CSS, etc. | ||
837 | class TestProgram(unittest.TestProgram): | ||
838 | """ | ||
839 | A variation of the unittest.TestProgram. Please refer to the base | ||
840 | class for command line parameters. | ||
841 | """ | ||
842 | def runTests(self): | ||
843 | # Pick HTMLTestRunner as the default test runner. | ||
844 | # base class's testRunner parameter is not useful because it means | ||
845 | # we have to instantiate HTMLTestRunner before we know self.verbosity. | ||
846 | if self.testRunner is None: | ||
847 | self.testRunner = HTMLTestRunner(verbosity=self.verbosity) | ||
848 | unittest.TestProgram.runTests(self) | ||
849 | |||
850 | main = TestProgram | ||
851 | |||
852 | ############################################################################## | ||
853 | # Executing this module from the command line | ||
854 | ############################################################################## | ||
855 | |||
856 | if __name__ == "__main__": | ||
857 | main(module=None) | ||
858 |
HTMLTestRunner.pyc
No preview for this file type
HTMLTestRunner_bak.py
File was created | 1 | """ | |
2 | A TestRunner for use with the Python unit testing framework. It | ||
3 | generates a HTML report to show the result at a glance. | ||
4 | |||
5 | The simplest way to use this is to invoke its main method. E.g. | ||
6 | |||
7 | import unittest | ||
8 | import HTMLTestRunner | ||
9 | |||
10 | ... define your tests ... | ||
11 | |||
12 | if __name__ == '__main__': | ||
13 | HTMLTestRunner.main() | ||
14 | |||
15 | |||
16 | For more customization options, instantiates a HTMLTestRunner object. | ||
17 | HTMLTestRunner is a counterpart to unittest's TextTestRunner. E.g. | ||
18 | |||
19 | # output to a file | ||
20 | fp = file('my_report.html', 'wb') | ||
21 | runner = HTMLTestRunner.HTMLTestRunner( | ||
22 | stream=fp, | ||
23 | title='My unit test', | ||
24 | description='This demonstrates the report output by HTMLTestRunner.' | ||
25 | ) | ||
26 | |||
27 | # Use an external stylesheet. | ||
28 | # See the Template_mixin class for more customizable options | ||
29 | runner.STYLESHEET_TMPL = '<link rel="stylesheet" href="my_stylesheet.css" type="text/css">' | ||
30 | |||
31 | # run the test | ||
32 | runner.run(my_test_suite) | ||
33 | |||
34 | |||
35 | ------------------------------------------------------------------------ | ||
36 | Copyright (c) 2004-2007, Wai Yip Tung | ||
37 | All rights reserved. | ||
38 | |||
39 | Redistribution and use in source and binary forms, with or without | ||
40 | modification, are permitted provided that the following conditions are | ||
41 | met: | ||
42 | |||
43 | * Redistributions of source code must retain the above copyright notice, | ||
44 | this list of conditions and the following disclaimer. | ||
45 | * Redistributions in binary form must reproduce the above copyright | ||
46 | notice, this list of conditions and the following disclaimer in the | ||
47 | documentation and/or other materials provided with the distribution. | ||
48 | * Neither the name Wai Yip Tung nor the names of its contributors may be | ||
49 | used to endorse or promote products derived from this software without | ||
50 | specific prior written permission. | ||
51 | |||
52 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS | ||
53 | IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED | ||
54 | TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A | ||
55 | PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER | ||
56 | OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, | ||
57 | EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | ||
58 | PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR | ||
59 | PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF | ||
60 | LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING | ||
61 | NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS | ||
62 | SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | ||
63 | """ | ||
64 | |||
65 | # URL: http://tungwaiyip.info/software/HTMLTestRunner.html | ||
66 | |||
67 | __author__ = "Wai Yip Tung" | ||
68 | __version__ = "0.8.2" | ||
69 | |||
70 | |||
71 | """ | ||
72 | Change History | ||
73 | |||
74 | Version 0.8.2 | ||
75 | * Show output inline instead of popup window (Viorel Lupu). | ||
76 | |||
77 | Version in 0.8.1 | ||
78 | * Validated XHTML (Wolfgang Borgert). | ||
79 | * Added description of test classes and test cases. | ||
80 | |||
81 | Version in 0.8.0 | ||
82 | * Define Template_mixin class for customization. | ||
83 | * Workaround a IE 6 bug that it does not treat <script> block as CDATA. | ||
84 | |||
85 | Version in 0.7.1 | ||
86 | * Back port to Python 2.3 (Frank Horowitz). | ||
87 | * Fix missing scroll bars in detail log (Podi). | ||
88 | """ | ||
89 | |||
90 | # TODO: color stderr | ||
91 | # TODO: simplify javascript using ,ore than 1 class in the class attribute? | ||
92 | |||
93 | import datetime | ||
94 | import io | ||
95 | import sys | ||
96 | import time | ||
97 | import unittest | ||
98 | from xml.sax import saxutils | ||
99 | |||
100 | |||
101 | # ------------------------------------------------------------------------ | ||
102 | # The redirectors below are used to capture output during testing. Output | ||
103 | # sent to sys.stdout and sys.stderr are automatically captured. However | ||
104 | # in some cases sys.stdout is already cached before HTMLTestRunner is | ||
105 | # invoked (e.g. calling logging.basicConfig). In order to capture those | ||
106 | # output, use the redirectors for the cached stream. | ||
107 | # | ||
108 | # e.g. | ||
109 | # >>> logging.basicConfig(stream=HTMLTestRunner.stdout_redirector) | ||
110 | # >>> | ||
111 | |||
112 | class OutputRedirector(object): | ||
113 | """ Wrapper to redirect stdout or stderr """ | ||
114 | def __init__(self, fp): | ||
115 | self.fp = fp | ||
116 | |||
117 | def write(self, s): | ||
118 | self.fp.write(s) | ||
119 | |||
120 | def writelines(self, lines): | ||
121 | self.fp.writelines(lines) | ||
122 | |||
123 | def flush(self): | ||
124 | self.fp.flush() | ||
125 | |||
126 | stdout_redirector = OutputRedirector(sys.stdout) | ||
127 | stderr_redirector = OutputRedirector(sys.stderr) | ||
128 | |||
129 | |||
130 | |||
131 | # ---------------------------------------------------------------------- | ||
132 | # Template | ||
133 | |||
134 | class Template_mixin(object): | ||
135 | """ | ||
136 | Define a HTML template for report customerization and generation. | ||
137 | |||
138 | Overall structure of an HTML report | ||
139 | |||
140 | HTML | ||
141 | +------------------------+ | ||
142 | |<html> | | ||
143 | | <head> | | ||
144 | | | | ||
145 | | STYLESHEET | | ||
146 | | +----------------+ | | ||
147 | | | | | | ||
148 | | +----------------+ | | ||
149 | | | | ||
150 | | </head> | | ||
151 | | | | ||
152 | | <body> | | ||
153 | | | | ||
154 | | HEADING | | ||
155 | | +----------------+ | | ||
156 | | | | | | ||
157 | | +----------------+ | | ||
158 | | | | ||
159 | | REPORT | | ||
160 | | +----------------+ | | ||
161 | | | | | | ||
162 | | +----------------+ | | ||
163 | | | | ||
164 | | ENDING | | ||
165 | | +----------------+ | | ||
166 | | | | | | ||
167 | | +----------------+ | | ||
168 | | | | ||
169 | | </body> | | ||
170 | |</html> | | ||
171 | +------------------------+ | ||
172 | """ | ||
173 | |||
174 | STATUS = { | ||
175 | 0: 'pass', | ||
176 | 1: 'fail', | ||
177 | 2: 'error', | ||
178 | } | ||
179 | |||
180 | DEFAULT_TITLE = 'Unit Test Report' | ||
181 | DEFAULT_DESCRIPTION = '' | ||
182 | |||
183 | # ------------------------------------------------------------------------ | ||
184 | # HTML Template | ||
185 | |||
186 | HTML_TMPL = r"""<?xml version="1.0" encoding="UTF-8"?> | ||
187 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
188 | <html xmlns="http://www.w3.org/1999/xhtml"> | ||
189 | <head> | ||
190 | <title>%(title)s</title> | ||
191 | <meta name="generator" content="%(generator)s"/> | ||
192 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||
193 | %(stylesheet)s | ||
194 | </head> | ||
195 | <body> | ||
196 | <script language="javascript" type="text/javascript"><!-- | ||
197 | output_list = Array(); | ||
198 | |||
199 | /* level - 0:Summary; 1:Failed; 2:All */ | ||
200 | function showCase(level) { | ||
201 | trs = document.getElementsByTagName("tr"); | ||
202 | for (var i = 0; i < trs.length; i++) { | ||
203 | tr = trs[i]; | ||
204 | id = tr.id; | ||
205 | if (id.substr(0,2) == 'ft') { | ||
206 | if (level < 1) { | ||
207 | tr.className = 'hiddenRow'; | ||
208 | } | ||
209 | else { | ||
210 | tr.className = ''; | ||
211 | } | ||
212 | } | ||
213 | if (id.substr(0,2) == 'pt') { | ||
214 | if (level > 1) { | ||
215 | tr.className = ''; | ||
216 | } | ||
217 | else { | ||
218 | tr.className = 'hiddenRow'; | ||
219 | } | ||
220 | } | ||
221 | } | ||
222 | } | ||
223 | |||
224 | |||
225 | function showClassDetail(cid, count) { | ||
226 | var id_list = Array(count); | ||
227 | var toHide = 1; | ||
228 | for (var i = 0; i < count; i++) { | ||
229 | tid0 = 't' + cid.substr(1) + '.' + (i+1); | ||
230 | tid = 'f' + tid0; | ||
231 | tr = document.getElementById(tid); | ||
232 | if (!tr) { | ||
233 | tid = 'p' + tid0; | ||
234 | tr = document.getElementById(tid); | ||
235 | } | ||
236 | id_list[i] = tid; | ||
237 | if (tr.className) { | ||
238 | toHide = 0; | ||
239 | } | ||
240 | } | ||
241 | for (var i = 0; i < count; i++) { | ||
242 | tid = id_list[i]; | ||
243 | if (toHide) { | ||
244 | document.getElementById('div_'+tid).style.display = 'none' | ||
245 | document.getElementById(tid).className = 'hiddenRow'; | ||
246 | } | ||
247 | else { | ||
248 | document.getElementById(tid).className = ''; | ||
249 | } | ||
250 | } | ||
251 | } | ||
252 | |||
253 | |||
254 | function showTestDetail(div_id){ | ||
255 | var details_div = document.getElementById(div_id) | ||
256 | var displayState = details_div.style.display | ||
257 | // alert(displayState) | ||
258 | if (displayState != 'block' ) { | ||
259 | displayState = 'block' | ||
260 | details_div.style.display = 'block' | ||
261 | } | ||
262 | else { | ||
263 | details_div.style.display = 'none' | ||
264 | } | ||
265 | } | ||
266 | |||
267 | |||
268 | function html_escape(s) { | ||
269 | s = s.replace(/&/g,'&'); | ||
270 | s = s.replace(/</g,'<'); | ||
271 | s = s.replace(/>/g,'>'); | ||
272 | return s; | ||
273 | } | ||
274 | |||
275 | /* obsoleted by detail in <div> | ||
276 | function showOutput(id, name) { | ||
277 | var w = window.open("", //url | ||
278 | name, | ||
279 | "resizable,scrollbars,status,width=800,height=450"); | ||
280 | d = w.document; | ||
281 | d.write("<pre>"); | ||
282 | d.write(html_escape(output_list[id])); | ||
283 | d.write("\n"); | ||
284 | d.write("<a href='javascript:window.close()'>close</a>\n"); | ||
285 | d.write("</pre>\n"); | ||
286 | d.close(); | ||
287 | } | ||
288 | */ | ||
289 | --></script> | ||
290 | |||
291 | %(heading)s | ||
292 | %(report)s | ||
293 | %(ending)s | ||
294 | |||
295 | </body> | ||
296 | </html> | ||
297 | """ | ||
298 | # variables: (title, generator, stylesheet, heading, report, ending) | ||
299 | |||
300 | |||
301 | # ------------------------------------------------------------------------ | ||
302 | # Stylesheet | ||
303 | # | ||
304 | # alternatively use a <link> for external style sheet, e.g. | ||
305 | # <link rel="stylesheet" href="$url" type="text/css"> | ||
306 | |||
307 | STYLESHEET_TMPL = """ | ||
308 | <style type="text/css" media="screen"> | ||
309 | body { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; } | ||
310 | table { font-size: 100%; } | ||
311 | pre { } | ||
312 | |||
313 | /* -- heading ---------------------------------------------------------------------- */ | ||
314 | h1 { | ||
315 | font-size: 16pt; | ||
316 | color: gray; | ||
317 | } | ||
318 | .heading { | ||
319 | margin-top: 0ex; | ||
320 | margin-bottom: 1ex; | ||
321 | } | ||
322 | |||
323 | .heading .attribute { | ||
324 | margin-top: 1ex; | ||
325 | margin-bottom: 0; | ||
326 | } | ||
327 | |||
328 | .heading .description { | ||
329 | margin-top: 4ex; | ||
330 | margin-bottom: 6ex; | ||
331 | } | ||
332 | |||
333 | /* -- css div popup ------------------------------------------------------------------------ */ | ||
334 | a.popup_link { | ||
335 | } | ||
336 | |||
337 | a.popup_link:hover { | ||
338 | color: red; | ||
339 | } | ||
340 | |||
341 | .popup_window { | ||
342 | display: none; | ||
343 | position: relative; | ||
344 | left: 0px; | ||
345 | top: 0px; | ||
346 | /*border: solid #627173 1px; */ | ||
347 | padding: 10px; | ||
348 | background-color: #E6E6D6; | ||
349 | font-family: "Lucida Console", "Courier New", Courier, monospace; | ||
350 | text-align: left; | ||
351 | font-size: 8pt; | ||
352 | width: 500px; | ||
353 | } | ||
354 | |||
355 | } | ||
356 | /* -- report ------------------------------------------------------------------------ */ | ||
357 | #show_detail_line { | ||
358 | margin-top: 3ex; | ||
359 | margin-bottom: 1ex; | ||
360 | } | ||
361 | #result_table { | ||
362 | width: 80%; | ||
363 | border-collapse: collapse; | ||
364 | border: 1px solid #777; | ||
365 | } | ||
366 | #header_row { | ||
367 | font-weight: bold; | ||
368 | color: white; | ||
369 | background-color: #777; | ||
370 | } | ||
371 | #result_table td { | ||
372 | border: 1px solid #777; | ||
373 | padding: 2px; | ||
374 | } | ||
375 | #total_row { font-weight: bold; } | ||
376 | .passClass { background-color: #6c6; } | ||
377 | .failClass { background-color: #c60; } | ||
378 | .errorClass { background-color: #c00; } | ||
379 | .passCase { color: #6c6; } | ||
380 | .failCase { color: #c60; font-weight: bold; } | ||
381 | .errorCase { color: #c00; font-weight: bold; } | ||
382 | .hiddenRow { display: none; } | ||
383 | .testcase { margin-left: 2em; } | ||
384 | |||
385 | |||
386 | /* -- ending ---------------------------------------------------------------------- */ | ||
387 | #ending { | ||
388 | } | ||
389 | |||
390 | </style> | ||
391 | """ | ||
392 | |||
393 | |||
394 | |||
395 | # ------------------------------------------------------------------------ | ||
396 | # Heading | ||
397 | # | ||
398 | |||
399 | HEADING_TMPL = """<div class='heading'> | ||
400 | <h1>%(title)s</h1> | ||
401 | %(parameters)s | ||
402 | <p class='description'>%(description)s</p> | ||
403 | </div> | ||
404 | |||
405 | """ # variables: (title, parameters, description) | ||
406 | |||
407 | HEADING_ATTRIBUTE_TMPL = """<p class='attribute'><strong>%(name)s:</strong> %(value)s</p> | ||
408 | """ # variables: (name, value) | ||
409 | |||
410 | |||
411 | |||
412 | # ------------------------------------------------------------------------ | ||
413 | # Report | ||
414 | # | ||
415 | |||
416 | REPORT_TMPL = """ | ||
417 | <p id='show_detail_line'>Show | ||
418 | <a href='javascript:showCase(0)'>Summary</a> | ||
419 | <a href='javascript:showCase(1)'>Failed</a> | ||
420 | <a href='javascript:showCase(2)'>All</a> | ||
421 | </p> | ||
422 | <table id='result_table'> | ||
423 | <colgroup> | ||
424 | <col align='left' /> | ||
425 | <col align='right' /> | ||
426 | <col align='right' /> | ||
427 | <col align='right' /> | ||
428 | <col align='right' /> | ||
429 | <col align='right' /> | ||
430 | </colgroup> | ||
431 | <tr id='header_row'> | ||
432 | <td>Test Group/Test case</td> | ||
433 | <td>Count</td> | ||
434 | <td>Pass</td> | ||
435 | <td>Fail</td> | ||
436 | <td>Error</td> | ||
437 | <td>View</td> | ||
438 | </tr> | ||
439 | %(test_list)s | ||
440 | <tr id='total_row'> | ||
441 | <td>Total</td> | ||
442 | <td>%(count)s</td> | ||
443 | <td>%(Pass)s</td> | ||
444 | <td>%(fail)s</td> | ||
445 | <td>%(error)s</td> | ||
446 | <td> </td> | ||
447 | </tr> | ||
448 | </table> | ||
449 | """ # variables: (test_list, count, Pass, fail, error) | ||
450 | |||
451 | REPORT_CLASS_TMPL = r""" | ||
452 | <tr class='%(style)s'> | ||
453 | <td>%(desc)s</td> | ||
454 | <td>%(count)s</td> | ||
455 | <td>%(Pass)s</td> | ||
456 | <td>%(fail)s</td> | ||
457 | <td>%(error)s</td> | ||
458 | <td><a href="javascript:showClassDetail('%(cid)s',%(count)s)">Detail</a></td> | ||
459 | </tr> | ||
460 | """ # variables: (style, desc, count, Pass, fail, error, cid) | ||
461 | |||
462 | |||
463 | REPORT_TEST_WITH_OUTPUT_TMPL = r""" | ||
464 | <tr id='%(tid)s' class='%(Class)s'> | ||
465 | <td class='%(style)s'><div class='testcase'>%(desc)s</div></td> | ||
466 | <td colspan='5' align='center'> | ||
467 | |||
468 | <!--css div popup start--> | ||
469 | <a class="popup_link" onfocus='this.blur();' href="javascript:showTestDetail('div_%(tid)s')" > | ||
470 | %(status)s</a> | ||
471 | |||
472 | <div id='div_%(tid)s' class="popup_window"> | ||
473 | <div style='text-align: right; color:red;cursor:pointer'> | ||
474 | <a onfocus='this.blur();' onclick="document.getElementById('div_%(tid)s').style.display = 'none' " > | ||
475 | [x]</a> | ||
476 | </div> | ||
477 | <pre> | ||
478 | %(script)s | ||
479 | </pre> | ||
480 | </div> | ||
481 | <!--css div popup end--> | ||
482 | |||
483 | </td> | ||
484 | </tr> | ||
485 | """ # variables: (tid, Class, style, desc, status) | ||
486 | |||
487 | |||
488 | REPORT_TEST_NO_OUTPUT_TMPL = r""" | ||
489 | <tr id='%(tid)s' class='%(Class)s'> | ||
490 | <td class='%(style)s'><div class='testcase'>%(desc)s</div></td> | ||
491 | <td colspan='5' align='center'>%(status)s</td> | ||
492 | </tr> | ||
493 | """ # variables: (tid, Class, style, desc, status) | ||
494 | |||
495 | |||
496 | REPORT_TEST_OUTPUT_TMPL = r""" | ||
497 | %(id)s: %(output)s | ||
498 | """ # variables: (id, output) | ||
499 | |||
500 | |||
501 | |||
502 | # ------------------------------------------------------------------------ | ||
503 | # ENDING | ||
504 | # | ||
505 | |||
506 | ENDING_TMPL = """<div id='ending'> </div>""" | ||
507 | |||
508 | # -------------------- The end of the Template class ------------------- | ||
509 | |||
510 | |||
511 | TestResult = unittest.TestResult | ||
512 | |||
513 | class _TestResult(TestResult): | ||
514 | # note: _TestResult is a pure representation of results. | ||
515 | # It lacks the output and reporting ability compares to unittest._TextTestResult. | ||
516 | |||
517 | def __init__(self, verbosity=1): | ||
518 | TestResult.__init__(self) | ||
519 | self.stdout0 = None | ||
520 | self.stderr0 = None | ||
521 | self.success_count = 0 | ||
522 | self.failure_count = 0 | ||
523 | self.error_count = 0 | ||
524 | self.verbosity = verbosity | ||
525 | |||
526 | # result is a list of result in 4 tuple | ||
527 | # ( | ||
528 | # result code (0: success; 1: fail; 2: error), | ||
529 | # TestCase object, | ||
530 | # Test output (byte string), | ||
531 | # stack trace, | ||
532 | # ) | ||
533 | self.result = [] | ||
534 | |||
535 | |||
536 | def startTest(self, test): | ||
537 | TestResult.startTest(self, test) | ||
538 | # just one buffer for both stdout and stderr | ||
539 | self.outputBuffer = io.StringIO() | ||
540 | stdout_redirector.fp = self.outputBuffer | ||
541 | stderr_redirector.fp = self.outputBuffer | ||
542 | self.stdout0 = sys.stdout | ||
543 | self.stderr0 = sys.stderr | ||
544 | sys.stdout = stdout_redirector | ||
545 | sys.stderr = stderr_redirector | ||
546 | |||
547 | |||
548 | def complete_output(self): | ||
549 | """ | ||
550 | Disconnect output redirection and return buffer. | ||
551 | Safe to call multiple times. | ||
552 | """ | ||
553 | if self.stdout0: | ||
554 | sys.stdout = self.stdout0 | ||
555 | sys.stderr = self.stderr0 | ||
556 | self.stdout0 = None | ||
557 | self.stderr0 = None | ||
558 | return self.outputBuffer.getvalue() | ||
559 | |||
560 | |||
561 | def stopTest(self, test): | ||
562 | # Usually one of addSuccess, addError or addFailure would have been called. | ||
563 | # But there are some path in unittest that would bypass this. | ||
564 | # We must disconnect stdout in stopTest(), which is guaranteed to be called. | ||
565 | self.complete_output() | ||
566 | |||
567 | |||
568 | def addSuccess(self, test): | ||
569 | self.success_count += 1 | ||
570 | TestResult.addSuccess(self, test) | ||
571 | output = self.complete_output() | ||
572 | self.result.append((0, test, output, '')) | ||
573 | if self.verbosity > 1: | ||
574 | sys.stderr.write('ok ') | ||
575 | sys.stderr.write(str(test)) | ||
576 | sys.stderr.write('\n') | ||
577 | else: | ||
578 | sys.stderr.write('.') | ||
579 | |||
580 | def addError(self, test, err): | ||
581 | self.error_count += 1 | ||
582 | TestResult.addError(self, test, err) | ||
583 | _, _exc_str = self.errors[-1] | ||
584 | output = self.complete_output() | ||
585 | self.result.append((2, test, output, _exc_str)) | ||
586 | if self.verbosity > 1: | ||
587 | sys.stderr.write('E ') | ||
588 | sys.stderr.write(str(test)) | ||
589 | sys.stderr.write('\n') | ||
590 | else: | ||
591 | sys.stderr.write('E') | ||
592 | |||
593 | def addFailure(self, test, err): | ||
594 | self.failure_count += 1 | ||
595 | TestResult.addFailure(self, test, err) | ||
596 | _, _exc_str = self.failures[-1] | ||
597 | output = self.complete_output() | ||
598 | self.result.append((1, test, output, _exc_str)) | ||
599 | if self.verbosity > 1: | ||
600 | sys.stderr.write('F ') | ||
601 | sys.stderr.write(str(test)) | ||
602 | sys.stderr.write('\n') | ||
603 | else: | ||
604 | sys.stderr.write('F') | ||
605 | |||
606 | |||
607 | class HTMLTestRunner(Template_mixin): | ||
608 | """ | ||
609 | """ | ||
610 | #def __init__(self, stream=sys.stdout, verbosity=1, title=None, description=None): | ||
611 | def __init__(self, outputdir, verbosity=1, title=None, description=None, report_name='test_report.html'): | ||
612 | #self.stream = self._create_output_file(outputdir, report_name) | ||
613 | self.outputdir = outputdir | ||
614 | self.report_name = report_name | ||
615 | self.verbosity = verbosity | ||
616 | if title is None: | ||
617 | self.title = self.DEFAULT_TITLE | ||
618 | else: | ||
619 | self.title = title | ||
620 | if description is None: | ||
621 | self.description = self.DEFAULT_DESCRIPTION | ||
622 | else: | ||
623 | self.description = description | ||
624 | |||
625 | self.startTime = datetime.datetime.now() | ||
626 | |||
627 | |||
628 | def _create_output_file(self, output, report_name): | ||
629 | import os | ||
630 | """ Generate the report file in the given path. """ | ||
631 | current_dir = os.getcwd() | ||
632 | dir_to = os.path.join(current_dir, output) | ||
633 | if not os.path.exists(dir_to): | ||
634 | os.makedirs(dir_to) | ||
635 | path_file = os.path.join(dir_to, report_name) | ||
636 | return path_file | ||
637 | |||
638 | |||
639 | def generateReport(self, test, result): | ||
640 | report_attrs = self.getReportAttributes(result) | ||
641 | generator = 'HTMLTestRunner %s' % __version__ | ||
642 | stylesheet = self._generate_stylesheet() | ||
643 | heading = self._generate_heading(report_attrs) | ||
644 | report = self._generate_report(result) | ||
645 | ending = self._generate_ending() | ||
646 | # output = self.HTML_TMPL % dict( | ||
647 | # title = saxutils.escape(self.title), | ||
648 | # generator = generator, | ||
649 | # stylesheet = stylesheet, | ||
650 | # heading = heading, | ||
651 | # report = report, | ||
652 | # ending = ending, | ||
653 | # ) | ||
654 | |||
655 | output = self.HTML_TMPL % dict( | ||
656 | title=saxutils.escape(self.title), | ||
657 | generator=generator, | ||
658 | stylesheet=stylesheet, | ||
659 | heading=heading, | ||
660 | report=report, | ||
661 | ending=ending, | ||
662 | ) | ||
663 | path_file = self._create_output_file(self.outputdir, self.report_name) | ||
664 | with open(path_file, 'w') as report_file: | ||
665 | report_file.write(output.encode('utf-8')) | ||
666 | |||
667 | |||
668 | def run(self, test): | ||
669 | "Run the given test case or test suite." | ||
670 | result = _TestResult(self.verbosity) | ||
671 | test(result) | ||
672 | self.stopTime = datetime.datetime.now() | ||
673 | self.generateReport(test, result) | ||
674 | # print >> sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime) | ||
675 | print(sys.stderr, '\nTime Elapsed: %s' % (self.stopTime-self.startTime)) | ||
676 | return result | ||
677 | |||
678 | |||
679 | def sortResult(self, result_list): | ||
680 | # unittest does not seems to run in any particular order. | ||
681 | # Here at least we want to group them together by class. | ||
682 | rmap = {} | ||
683 | classes = [] | ||
684 | for n,t,o,e in result_list: | ||
685 | cls = t.__class__ | ||
686 | if not cls in rmap: | ||
687 | rmap[cls] = [] | ||
688 | classes.append(cls) | ||
689 | rmap[cls].append((n,t,o,e)) | ||
690 | r = [(cls, rmap[cls]) for cls in classes] | ||
691 | return r | ||
692 | |||
693 | |||
694 | def getReportAttributes(self, result): | ||
695 | """ | ||
696 | Return report attributes as a list of (name, value). | ||
697 | Override this to add custom attributes. | ||
698 | """ | ||
699 | startTime = str(self.startTime)[:19] | ||
700 | duration = str(self.stopTime - self.startTime) | ||
701 | status = [] | ||
702 | if result.success_count: status.append('Pass %s' % result.success_count) | ||
703 | if result.failure_count: status.append('Failure %s' % result.failure_count) | ||
704 | if result.error_count: status.append('Error %s' % result.error_count ) | ||
705 | if status: | ||
706 | status = ' '.join(status) | ||
707 | else: | ||
708 | status = 'none' | ||
709 | return [ | ||
710 | ('Start Time', startTime), | ||
711 | ('Duration', duration), | ||
712 | ('Status', status), | ||
713 | ] | ||
714 | |||
715 | |||
716 | |||
717 | |||
718 | |||
719 | |||
720 | |||
721 | def _generate_stylesheet(self): | ||
722 | return self.STYLESHEET_TMPL | ||
723 | |||
724 | |||
725 | def _generate_heading(self, report_attrs): | ||
726 | a_lines = [] | ||
727 | for name, value in report_attrs: | ||
728 | line = self.HEADING_ATTRIBUTE_TMPL % dict( | ||
729 | name = saxutils.escape(name), | ||
730 | value = saxutils.escape(value), | ||
731 | ) | ||
732 | a_lines.append(line) | ||
733 | heading = self.HEADING_TMPL % dict( | ||
734 | title = saxutils.escape(self.title), | ||
735 | parameters = ''.join(a_lines), | ||
736 | description = saxutils.escape(self.description), | ||
737 | ) | ||
738 | return heading | ||
739 | |||
740 | |||
741 | def _generate_report(self, result): | ||
742 | rows = [] | ||
743 | sortedResult = self.sortResult(result.result) | ||
744 | for cid, (cls, cls_results) in enumerate(sortedResult): | ||
745 | # subtotal for a class | ||
746 | np = nf = ne = 0 | ||
747 | for n,t,o,e in cls_results: | ||
748 | if n == 0: np += 1 | ||
749 | elif n == 1: nf += 1 | ||
750 | else: ne += 1 | ||
751 | |||
752 | # format class description | ||
753 | if cls.__module__ == "__main__": | ||
754 | name = cls.__name__ | ||
755 | else: | ||
756 | name = "%s.%s" % (cls.__module__, cls.__name__) | ||
757 | doc = cls.__doc__ and cls.__doc__.split("\n")[0] or "" | ||
758 | desc = doc and '%s: %s' % (name, doc) or name | ||
759 | |||
760 | row = self.REPORT_CLASS_TMPL % dict( | ||
761 | style = ne > 0 and 'errorClass' or nf > 0 and 'failClass' or 'passClass', | ||
762 | desc = desc, | ||
763 | count = np+nf+ne, | ||
764 | Pass = np, | ||
765 | fail = nf, | ||
766 | error = ne, | ||
767 | cid = 'c%s' % (cid+1), | ||
768 | ) | ||
769 | rows.append(row) | ||
770 | |||
771 | for tid, (n,t,o,e) in enumerate(cls_results): | ||
772 | self._generate_report_test(rows, cid, tid, n, t, o, e) | ||
773 | |||
774 | report = self.REPORT_TMPL % dict( | ||
775 | test_list = ''.join(rows), | ||
776 | count = str(result.success_count+result.failure_count+result.error_count), | ||
777 | Pass = str(result.success_count), | ||
778 | fail = str(result.failure_count), | ||
779 | error = str(result.error_count), | ||
780 | ) | ||
781 | return report | ||
782 | |||
783 | |||
784 | def _generate_report_test(self, rows, cid, tid, n, t, o, e): | ||
785 | # e.g. 'pt1.1', 'ft1.1', etc | ||
786 | has_output = bool(o or e) | ||
787 | tid = (n == 0 and 'p' or 'f') + 't%s.%s' % (cid+1,tid+1) | ||
788 | name = t.id().split('.')[-1] | ||
789 | doc = t.shortDescription() or "" | ||
790 | desc = doc and ('%s: %s' % (name, doc)) or name | ||
791 | tmpl = has_output and self.REPORT_TEST_WITH_OUTPUT_TMPL or self.REPORT_TEST_NO_OUTPUT_TMPL | ||
792 | |||
793 | # o and e should be byte string because they are collected from stdout and stderr? | ||
794 | if isinstance(o,str): | ||
795 | # TODO: some problem with 'string_escape': it escape \n and mess up formating | ||
796 | # uo = unicode(o.encode('string_escape')) | ||
797 | # uo = o.decode('latin-1') | ||
798 | uo = e | ||
799 | else: | ||
800 | uo = o | ||
801 | if isinstance(e,str): | ||
802 | # TODO: some problem with 'string_escape': it escape \n and mess up formating | ||
803 | # ue = unicode(e.encode('string_escape')) | ||
804 | # ue = e.decode('latin-1') | ||
805 | ue = e | ||
806 | else: | ||
807 | ue = e | ||
808 | |||
809 | script = self.REPORT_TEST_OUTPUT_TMPL % dict( | ||
810 | id = tid, | ||
811 | output = saxutils.escape(str(uo)+ue), | ||
812 | ) | ||
813 | |||
814 | row = tmpl % dict( | ||
815 | tid = tid, | ||
816 | Class = (n == 0 and 'hiddenRow' or 'none'), | ||
817 | style = n == 2 and 'errorCase' or (n == 1 and 'failCase' or 'none'), | ||
818 | desc = desc, | ||
819 | script = script, | ||
820 | status = self.STATUS[n], | ||
821 | ) | ||
822 | rows.append(row) | ||
823 | if not has_output: | ||
824 | return | ||
825 | |||
826 | def _generate_ending(self): | ||
827 | return self.ENDING_TMPL | ||
828 | |||
829 | |||
830 | ############################################################################## | ||
831 | # Facilities for running tests from the command line | ||
832 | ############################################################################## | ||
833 | |||
834 | # Note: Reuse unittest.TestProgram to launch test. In the future we may | ||
835 | # build our own launcher to support more specific command line | ||
836 | # parameters like test title, CSS, etc. | ||
837 | class TestProgram(unittest.TestProgram): | ||
838 | """ | ||
839 | A variation of the unittest.TestProgram. Please refer to the base | ||
840 | class for command line parameters. | ||
841 | """ | ||
842 | def runTests(self): | ||
843 | # Pick HTMLTestRunner as the default test runner. | ||
844 | # base class's testRunner parameter is not useful because it means | ||
845 | # we have to instantiate HTMLTestRunner before we know self.verbosity. | ||
846 | if self.testRunner is None: | ||
847 | self.testRunner = HTMLTestRunner(verbosity=self.verbosity) | ||
848 | unittest.TestProgram.runTests(self) | ||
849 | |||
850 | main = TestProgram | ||
851 | |||
852 | ############################################################################## | ||
853 | # Executing this module from the command line | ||
854 | ############################################################################## | ||
855 | |||
856 | if __name__ == "__main__": | ||
857 | main(module=None) | ||
858 |
README
File was created | 1 | API test scripts about APIs in Pad3.o | |
2 |
__pycache__/HTMLTestRunner.cpython-36.pyc
No preview for this file type
__pycache__/HTMLTestRunner_bak.cpython-36.pyc
No preview for this file type
__pycache__/configParse.cpython-36.pyc
No preview for this file type
__pycache__/run_test.cpython-36.pyc
No preview for this file type
configParse.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import configparser | ||
5 | import pymysql.cursors | ||
6 | import os | ||
7 | |||
8 | base_dir = str(os.path.dirname(os.path.dirname(__file__))) | ||
9 | config_dir = base_dir.replace('\\', '/') | ||
10 | config_path = config_dir + '/config.ini' | ||
11 | |||
12 | cp = configparser.ConfigParser() | ||
13 | cp.read(config_path) | ||
14 | DB_host = cp.get('mysqlconf', 'host') | ||
15 | DB_port = cp.get('mysqlconf', 'port') | ||
16 | DB_username = cp.get('mysqlconf', 'user') | ||
17 | DB_password = cp.get('mysqlconf', 'password') | ||
18 | DB_dbName = cp.get('mysqlconf', 'db_name') | ||
19 | |||
20 | userPhone = cp.get('userinfo', 'userPhone') | ||
21 | deviceNumber = cp.get('userinfo','deviceNumber') | ||
22 | admin_host = 'http://admin.test.hjx.com/' | ||
23 | boss_host = 'http://boss.test.hjx.com/' |
data_fixture/__pycache__/config_data.cpython-36.pyc
No preview for this file type
data_fixture/__pycache__/create_testdata.cpython-36.pyc
No preview for this file type
data_fixture/__pycache__/mysql_db.cpython-36.pyc
No preview for this file type
data_fixture/config_data.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | # DB connection | ||
5 | DB_HOST='115.29.194.25' | ||
6 | DB_PORT=3307 | ||
7 | DB_USERNAME='cloud' | ||
8 | DB_PASSWORD='cloud123' | ||
9 | DB_DBNAME='acornuser' | ||
10 | |||
11 | |||
12 | # DB_host='192.168.4.135' | ||
13 | # DB_port=3306 | ||
14 | # DB_username='cloud' | ||
15 | # DB_password='wQHPo9H6s7' | ||
16 | # DB_db_name='acornuser' | ||
17 | |||
18 | HOST_BOSS = 'http://boss.test.hjx.com' | ||
19 | HOST_ADMIN = 'http://admin.test.hjx.com' | ||
20 | HOST_STA = 'http://sta.test.hjx.com' | ||
21 | HOST_RES = 'http://res.test.hjx.com' | ||
22 | |||
23 | #USER_ID = '90000000123456' | ||
24 | |||
25 | USER_ID = '7000000054686773' | ||
26 | USER_ID_INCOMPLETE = '7000000054686777' #注册未完成账号 | ||
27 | USER_ID_VIDEO = '7000000054686773' | ||
28 | USER_ID_NO_VIDEO = '7000000054686776' | ||
29 | MODEL = 'AAAAA' | ||
30 | USER_PHONE = '13811111111' # 注册登陆 | ||
31 | USER_PHONE_EDIT = '13811111122' # 修改保卡 | ||
32 | USER_PHONE_CHANGE = '13811111133' # 修改手机号 | ||
33 | USER_PHONE_CHANGE_EXISTS = '13811111166' | ||
34 | USER_PHONE_USED = '13811111144' | ||
35 | USER_PHONE_UNUSED = '13811111155' | ||
36 | |||
37 | |||
38 | PARENT_ID = '7000000054686775' | ||
39 | |||
40 | |||
41 | ## 保卡 ------------------------ | ||
42 | # 客机,已绑定保卡 | ||
43 | DEVICE_NUMBER_CUS_BIND = 'CUSBIND123456789' | ||
44 | MAC_CUS_BIND = '00:00:00:00:00:11' | ||
45 | # 客机, 没有保卡 | ||
46 | DEVICE_NUMBER_CUS_UNBIND = 'CUSUNBIND123456789' | ||
47 | MAC_CUS_UNBIND = '00:00:00:00:00:22' | ||
48 | # 样机 | ||
49 | DEVICE_NUMBER_SAM = 'SAM123456789' | ||
50 | MAC_SAM = '00:00:00:00:00:33' | ||
51 | |||
52 | #添加客机保卡 | ||
53 | DEVICE_NUMBER_NEW = 'NEW123456789' | ||
54 | MAC_NEW = '00:00:00:00:00:44' | ||
55 | |||
56 | # 置为样机,提交终端信息 | ||
57 | DEVICE_NUMBER_TO_SAM = 'TOSAM123456789' | ||
58 | |||
59 | #置为客机 | ||
60 | DEVICE_NUMBER_TO_CUS = 'TOCUS123456789' | ||
61 | |||
62 | #解绑保卡 | ||
63 | DEVICE_NUMBER_UNBIND = 'UNBIND123456789' | ||
64 | |||
65 | #修改保卡 | ||
66 | DEVICE_NUMBER_EDIT = 'EDIT123456789' | ||
67 | |||
68 | |||
69 | ## 子账户 ----------------------- | ||
70 | #子账户头像 | ||
71 | SUB_ACC_IMAGE = 'http://hjxprodbucket.oss.aliyuncs.com/static/upload/boss_api/announcement/2017-08-29/a00de899-2f6d-43fb-9e30-71883842540e.png' | ||
72 | #子账户区域 | ||
73 | SUB_ACC_REGION_NAME_1 = '河北秦皇岛青龙' | ||
74 | SUB_ACC_REGION_NAME_2 = '江苏南京玄武' | ||
75 | #子账户区域ID | ||
76 | SUB_ACC_REGION_ID_1 = 130321 | ||
77 | SUB_ACC_REGION_ID_2 = 320102 | ||
78 | #子账户学校ID | ||
79 | SUB_ACC_SCHOOL_ID_1 = 43470 ## 小学 | ||
80 | SUB_ACC_SCHOOL_ID_2 = 500016 ## 中学 | ||
81 | |||
82 | |||
83 | |||
84 | |||
85 | |||
86 |
data_fixture/create_testdata.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | from data_fixture.mysql_db import DB | ||
5 | from data_fixture import config_data as Data | ||
6 | from datetime import datetime, date, timedelta | ||
7 | import time | ||
8 | from data_fixture.config_data import HOST_BOSS | ||
9 | import requests | ||
10 | import calendar | ||
11 | import uuid | ||
12 | |||
13 | |||
14 | db = DB() | ||
15 | |||
16 | ## ********************************************************************************************************************* | ||
17 | ## 验证码 | ||
18 | ## ********************************************************************************************************************* | ||
19 | def fet_authCode(mobile): | ||
20 | url = HOST_BOSS + "/ozing/timer/user/fetchAuthCode" | ||
21 | headers = {'Accept': '*/*'} | ||
22 | postData = {'mobile': mobile, 'type': 'general'} | ||
23 | r = requests.post(url, headers=headers, data=postData) | ||
24 | result = r.json() | ||
25 | if result['status'] == 100: | ||
26 | return result['jsessionid'] | ||
27 | else : | ||
28 | raise FetchException('fetch auth code Error!') | ||
29 | |||
30 | |||
31 | class FetchException(Exception): | ||
32 | pass | ||
33 | |||
34 | ## ********************************************************************************************************************* | ||
35 | ## 保卡 | ||
36 | ## ********************************************************************************************************************* | ||
37 | # 保卡数据 -- 新建保卡 | ||
38 | def pre_elecCard(device_cus_bind='0', device_sam='0', device_cus_unbind='0'): | ||
39 | |||
40 | if device_cus_bind != '0': | ||
41 | # 客机,已绑定保卡 | ||
42 | select_customermachine = "select * from acornuser.ozing_customermachine where deviceNumber = '{}' ".format(device_cus_bind) | ||
43 | select_machine_cus = "SELECT * FROM acornuser.ozing_machine where deviceNumber = '{}' ".format(device_cus_bind) | ||
44 | insert_customermachine_tabel = 'acornuser.ozing_customermachine' | ||
45 | insert_customermachine_data = { | ||
46 | 'deviceNumber': device_cus_bind, | ||
47 | 'userId': Data.USER_ID, | ||
48 | 'customerName':'测试customer', | ||
49 | 'customerAddress':'内蒙古巴彦淖尔市', | ||
50 | 'customerPhone':'13822222222', | ||
51 | 'buyTime': datetime.now().strftime("%Y-%m-%d %H:%M:%S"), | ||
52 | 'buyAddress':'内蒙古巴彦淖尔市', | ||
53 | 'alterSaleCall':'51518888', | ||
54 | 'cmstate': '1', | ||
55 | 'createTime': datetime.now().strftime("%Y-%m-%d %H:%M:%S") | ||
56 | } | ||
57 | insert_machine_cus_table = 'acornuser.ozing_machine' | ||
58 | insert_machine_cus_data = {'productModel': Data.MODEL, | ||
59 | 'deviceNumber': device_cus_bind, | ||
60 | 'macAddress': Data.MAC_CUS_BIND, | ||
61 | 'state': '1' | ||
62 | } | ||
63 | if db.select(select_customermachine): | ||
64 | pass | ||
65 | else: | ||
66 | db.insert(insert_customermachine_tabel, insert_customermachine_data) | ||
67 | |||
68 | if db.select(select_machine_cus): | ||
69 | pass | ||
70 | else: | ||
71 | db.insert(insert_machine_cus_table, insert_machine_cus_data) | ||
72 | |||
73 | # 样机 | ||
74 | if device_sam !='0': | ||
75 | select_samplemachine = "SELECT * FROM acornuser.ozing_samplemachine where deviceNumber = '{}' ".format(device_sam) | ||
76 | select_machine_sam = "SELECT * FROM acornuser.ozing_machine where deviceNumber = '{}' ".format(device_sam) | ||
77 | insert_samplemachine_tabel = 'acornuser.ozing_samplemachine' | ||
78 | insert_samplemachine_data= {'deviceNumber': device_sam, | ||
79 | 'userId': Data.USER_ID, | ||
80 | 'terminalAddress': "内蒙古巴彦淖尔市", | ||
81 | 'distributor': "新华书店", | ||
82 | 'saleClerk':"张三", | ||
83 | 'mobilePhone': "18622222222", | ||
84 | 'photo':'[{"photoUrl":"static/upload/online_api/samplePhoto/2017-12-13/b6480129-e720-4109-a455-6130fd640f16.jpg"},{"photoUrl":"static/upload/online_api/samplePhoto/2017-12-13/b8317fa4-cfa5-4ea4-91d4-3ca020e06bca.jpg"},{"photoUrl":"static/upload/online_api/samplePhoto/2017-12-13/110dc30b-34f1-4e0b-88e0-a030b8ab4af7.jpg"}]', | ||
85 | 'smstate': '1', | ||
86 | 'createTime': datetime.now().strftime('%Y-%m-%d %H:%M:%S') } | ||
87 | insert_machine_sam_tabel = 'acornuser.ozing_machine' | ||
88 | insert_machine_sam_data = {'productModel': Data.MODEL, | ||
89 | 'deviceNumber': device_sam, | ||
90 | 'macAddress': Data.MAC_SAM, | ||
91 | 'state': '0'} | ||
92 | |||
93 | if db.select(select_samplemachine): | ||
94 | pass | ||
95 | else: | ||
96 | db.insert(insert_samplemachine_tabel, insert_samplemachine_data) | ||
97 | |||
98 | if db.select(select_machine_sam): | ||
99 | pass | ||
100 | else: | ||
101 | db.insert(insert_machine_sam_tabel, insert_machine_sam_data) | ||
102 | |||
103 | # 未绑定 -- 客机 | ||
104 | if device_cus_unbind != '0': | ||
105 | select_customermachine_unbind = "select * from acornuser.ozing_customermachine where deviceNumber = '{}' " \ | ||
106 | .format(device_cus_unbind) | ||
107 | update_customermachine_unbind_tabel = 'acornuser.ozing_customermachine' | ||
108 | update_customermachine_unbind_set = {'deviceNumber':str(time.time())} | ||
109 | update_customermachine_unbind_where = {'deviceNumber': device_cus_unbind} | ||
110 | |||
111 | select_machine_cus_1 = "SELECT * FROM acornuser.ozing_machine where deviceNumber = '{}' ".format(device_cus_unbind) | ||
112 | select_machine_cus_2 = "SELECT * FROM acornuser.ozing_machine where deviceNumber = '{}' and state = '1' ".format(device_cus_unbind) | ||
113 | |||
114 | update_machine_cus_unbind_table = 'acornuser.ozing_machine' | ||
115 | update_machine_cus_unbind_set = {'state': '1'} | ||
116 | update_machine_cus_unbind_where = {'deviceNumber': device_cus_unbind} | ||
117 | |||
118 | # 保卡表中有数据 | ||
119 | if db.select(select_customermachine_unbind): | ||
120 | db.update(update_customermachine_unbind_tabel, update_customermachine_unbind_set, update_customermachine_unbind_where) | ||
121 | # 机器表中有数据,并且状态是1 | ||
122 | if db.select(select_machine_cus_1): | ||
123 | if db.select(select_machine_cus_2): | ||
124 | pass | ||
125 | else: | ||
126 | # update state =1 | ||
127 | db.update(update_machine_cus_unbind_table, update_machine_cus_unbind_set, update_machine_cus_unbind_where) | ||
128 | # 机器表中没数据 | ||
129 | else: | ||
130 | pass | ||
131 | |||
132 | # #添加客机保卡 | ||
133 | def pre_SetUpElecCard(): | ||
134 | select_customermachine_new = "select * from acornuser.ozing_customermachine where deviceNumber = '{}' ".format(Data.DEVICE_NUMBER_NEW) | ||
135 | update_customermachine_new_tabel = 'acornuser.ozing_customermachine' | ||
136 | update_customermachine_new_set = {'deviceNumber':str(time.time())} | ||
137 | update_customermachine_new_where = {'deviceNumber': Data.DEVICE_NUMBER_NEW} | ||
138 | |||
139 | select_machine_new = "select * from acornuser.ozing_machine where deviceNumber = '{}' ".format(Data.DEVICE_NUMBER_NEW) | ||
140 | update_machine_new_tabel = 'acornuser.ozing_machine' | ||
141 | update_machine_new_set = {'deviceNumber': str(time.time())} | ||
142 | update_machine_new_where = {'deviceNumber': Data.DEVICE_NUMBER_NEW} | ||
143 | |||
144 | if db.select(select_customermachine_new): | ||
145 | db.update(update_customermachine_new_tabel, update_customermachine_new_set, update_customermachine_new_where) | ||
146 | if db.select(select_machine_new): | ||
147 | db.update(update_machine_new_tabel, update_machine_new_set, update_machine_new_where) | ||
148 | |||
149 | |||
150 | ## ********************************************************************************************************************* | ||
151 | ## 子账户 | ||
152 | ## ********************************************************************************************************************* | ||
153 | |||
154 | def pre_subAccount(parent_id, sub_account_id, status, deviceNumber=Data.DEVICE_NUMBER_CUS_BIND): #status: child status | ||
155 | |||
156 | # 子账户数据 | ||
157 | TABEL_CHILD_USER = 'acornuser.child_user' | ||
158 | if status == 1 : # make sure only 1 sub account's status marked as '1' | ||
159 | update_all_0_sub = "update acornuser.child_user set status = 0 where parent_id = '{}' and deviceNumber = '{}'" \ | ||
160 | .format(parent_id, deviceNumber) | ||
161 | db.update_(update_all_0_sub) | ||
162 | |||
163 | select_sub_acc = "select * from acornuser.child_user where parent_id = '{}' and subAccountId = '{}' ".format(parent_id, sub_account_id) | ||
164 | select_sub_acc_status = "select * from acornuser.child_user where parent_id = '{}' and subAccountId = '{}' " \ | ||
165 | "and status = {} ".format(parent_id, sub_account_id, status) | ||
166 | update_set = {'status': status} | ||
167 | update_where = {'subAccountId': sub_account_id } | ||
168 | insert_data = {'parent_id':parent_id, | ||
169 | 'image': Data.SUB_ACC_IMAGE, | ||
170 | 'name' : '测试sub', | ||
171 | 'grade_id':'6', | ||
172 | 'school_id': Data.SUB_ACC_SCHOOL_ID_2, | ||
173 | 'region_id': Data.SUB_ACC_REGION_ID_2, | ||
174 | 'status':status, | ||
175 | 'region_name': Data.SUB_ACC_REGION_NAME_2, | ||
176 | 'deviceNumber':Data.DEVICE_NUMBER_CUS_BIND, | ||
177 | 'subAccountId':sub_account_id | ||
178 | } | ||
179 | |||
180 | if db.select(select_sub_acc_status): | ||
181 | pass | ||
182 | elif db.select(select_sub_acc): | ||
183 | db.update(TABEL_CHILD_USER, update_set, update_where) | ||
184 | else: | ||
185 | db.insert(TABEL_CHILD_USER, insert_data) | ||
186 | |||
187 | |||
188 | #主账户数据 | ||
189 | select_acc_1 = "select * from acornuser.acorn_user_status where userId = '{}' and deviceNumber = '{}' " \ | ||
190 | .format(parent_id, deviceNumber) | ||
191 | if status == 1: # if child status == 1, parent status should be 0 | ||
192 | select_acc_2 = "select * from acornuser.acorn_user_status where userId = '{}' and deviceNumber = '{}' and status = 0 " \ | ||
193 | .format(parent_id, deviceNumber) | ||
194 | |||
195 | insert_data_parent_0 = {'userId': parent_id, | ||
196 | 'status': 0, | ||
197 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
198 | } | ||
199 | set_0 = {'status': 0} | ||
200 | where = {'userId': parent_id, | ||
201 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
202 | } | ||
203 | |||
204 | if db.select(select_acc_2): | ||
205 | pass | ||
206 | elif db.select(select_acc_1): | ||
207 | db.update("acornuser.acorn_user_status", set_0, where) | ||
208 | else: | ||
209 | db.insert("acornuser.acorn_user_status", insert_data_parent_0) | ||
210 | else: # if child status == 0, parent status should be 1 | ||
211 | select_acc_3 = "select * from acornuser.acorn_user_status where userId = '{}' and deviceNumber = '{}' and status = 1 " \ | ||
212 | .format(parent_id, deviceNumber) | ||
213 | set_1 = {'status': 1} | ||
214 | where = {'userId': parent_id, | ||
215 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
216 | } | ||
217 | insert_data_parent_1 = {'userId': parent_id, | ||
218 | 'status': 1, | ||
219 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
220 | } | ||
221 | if db.select(select_acc_3): | ||
222 | pass | ||
223 | elif db.select(select_acc_1): | ||
224 | db.update("acornuser.acorn_user_status", set_1, where) | ||
225 | else: | ||
226 | db.insert("acornuser.acorn_user_status", insert_data_parent_1) | ||
227 | |||
228 | |||
229 | |||
230 | |||
231 | # 删除对应的parentID的所有数据 便于验证添加成功 | ||
232 | def pre_AddSubAccount(parent_Id): | ||
233 | where_data = {'parent_Id': parent_Id} | ||
234 | set_data = {'parent_Id': calendar.timegm(time.gmtime())} | ||
235 | if db.select_('acornuser.child_user', where_data): | ||
236 | db.update('acornuser.child_user', set_data, where_data) | ||
237 | |||
238 | |||
239 | #检查signature存在 | ||
240 | def checkSignatureExists(userId, type): | ||
241 | #主账户 | ||
242 | if type == 1: | ||
243 | sql_1 = 'select * from acornuser.acorn_user_extra where user_id = {} '.format(userId) | ||
244 | sql_2 = 'select * from acornuser.acorn_user_extra where user_id = {} and signature is not NULL'.format(userId) | ||
245 | |||
246 | if db.select(sql_2): | ||
247 | pass | ||
248 | elif db.select(sql_1): | ||
249 | set = {'signature': '聪明的波利'} | ||
250 | where = {'user_id': userId} | ||
251 | db.update('acornuser.acorn_user_extra', set, where) | ||
252 | else: | ||
253 | insert = {'user_id': userId, 'signature': '聪明的波利'} | ||
254 | db.insert('acornuser.acorn_user_extra', insert) | ||
255 | |||
256 | # 子账户 | ||
257 | if type == 2: | ||
258 | sql_1 = "select * from acornuser.subAccount_user_extra where sub_account_id = '{}' ".format(userId) | ||
259 | sql_2 = "select * from acornuser.subAccount_user_extra where sub_account_id = '{}'and signature is not NULL".format(userId) | ||
260 | |||
261 | if db.select(sql_2): | ||
262 | pass | ||
263 | elif db.select(sql_1): | ||
264 | set = {'signature': '聪明的波利 sub~'} | ||
265 | where = {'sub_account_id': userId} | ||
266 | db.update('acornuser.subAccount_user_extra', set, where) | ||
267 | else: | ||
268 | insert = {'sub_account_id': userId, 'signature': '聪明的波利 sub~'} | ||
269 | db.insert('acornuser.subAccount_user_extra', insert) | ||
270 | |||
271 | |||
272 | ## ********************************************************************************************************************* | ||
273 | ## 教材版本 | ||
274 | ## ********************************************************************************************************************* | ||
275 | |||
276 | # 用户版本信息 | ||
277 | def pre_GetUserPressInfo(userId): | ||
278 | set = {'chinese': '北京师范大学出版社'} | ||
279 | where = {'user_id': userId} | ||
280 | db.update('acornuser.user_press', set, where) | ||
281 | |||
282 | |||
283 | ## ********************************************************************************************************************* | ||
284 | ## 登录注册 | ||
285 | ## ********************************************************************************************************************* | ||
286 | # 检查用户注册信息是否完整 | ||
287 | def pre_register_extrainfo_check(user_id, complete): | ||
288 | #不完整 | ||
289 | if complete == False: | ||
290 | sql = "select * from acornuser.ozing_student where user_id = {} and region_id is NULL and school_id is NULL".format(user_id) | ||
291 | if db.select(sql): | ||
292 | pass | ||
293 | else: | ||
294 | update_sql = "update acornuser.ozing_student set region_id = NULL, school_id = NULL where user_id = {}".format(user_id) | ||
295 | db.update_(update_sql) | ||
296 | |||
297 | # 完整 | ||
298 | else: | ||
299 | sql = "select * from acornuser.ozing_student where user_id = {} and region_id is not NULL and school_id is not NULL".format( | ||
300 | user_id) | ||
301 | if db.select(sql): | ||
302 | pass | ||
303 | else: | ||
304 | set = {'region_id': '140600', 'school_id': '496299', 'region_name':'江苏苏州吴中'} | ||
305 | where = {'user_id': user_id} | ||
306 | db.update('acornuser.ozing_student', set, where) | ||
307 | |||
308 | ## ********************************************************************************************************************* | ||
309 | ## 最近观看视频 | ||
310 | ## ********************************************************************************************************************* | ||
311 | def pre_getRecentVideo(user_id, status): # status=0 novideo, status=1 has video | ||
312 | where = {'user_id': user_id} | ||
313 | if status == 0 : | ||
314 | set = {'user_id': str(time.time())} | ||
315 | if db.select_('acornuser.user_video_watch', where): | ||
316 | db.update('acornuser.user_video_watch', set, where) | ||
317 | |||
318 | if status == 1 : | ||
319 | if db.select_('acornuser.user_video_watch', where): | ||
320 | pass | ||
321 | else: | ||
322 | insert_data = {'user_id': user_id, | ||
323 | 'data_id': 486600, | ||
324 | 'data_name':'人教7上_1 春_程诗尧.mpc', | ||
325 | 'play_online_url':'http://fd.xuexiao100.com/mp4/黄冈视频/初中语文/7年级上 人民教育出版社_2017版/人教7上_1 春_程诗尧.mp4?k=e8f8a7429a42aff00cb96faa6f48821e', | ||
326 | 'cover_url': 'http://hjxprodbucket.oss.aliyuncs.com/static/upload/boss_api/announcement/2017-10-18/34cfe338-2305-4aa0-96d8-c952be4dd800.jpg', | ||
327 | 'app_unique_name': 'famous-teacher', | ||
328 | 'created_time': '2017-12-27 14:52:08', | ||
329 | 'modified_time': '2017-12-27 14:52:08' | ||
330 | } | ||
331 | db.insert('acornuser.user_video_watch', insert_data) | ||
332 | |||
333 | ## ********************************************************************************************************************* | ||
334 | ## 手机号重复验证 | ||
335 | ## ********************************************************************************************************************* | ||
336 | def pre_phoneUsedCheck(phone, used): #used = True :used | ||
337 | where = {'username': phone} | ||
338 | if used: | ||
339 | if db.select_('acornuser.acorn_user', where): | ||
340 | pass | ||
341 | else: | ||
342 | max_id = db.select('select max(id) from acornuser.acorn_user')[0]['max(id)'] | ||
343 | update_where = {'id': max_id - 150} | ||
344 | count = db.select_('acornuser.acorn_user', update_where) | ||
345 | |||
346 | db.update('acornuser.acorn_user', where, update_where) | ||
347 | else: | ||
348 | if db.select_('acornuser.acorn_user', where): | ||
349 | update_set = {'username': str(time.time())} | ||
350 | db.update('acornuser.acorn_user', update_set, where) | ||
351 | |||
352 | |||
353 | ## ********************************************************************************************************************* | ||
354 | ## 家长控制 密码 | ||
355 | ## ********************************************************************************************************************* | ||
356 | def get_parentSpace_password(device_number): | ||
357 | sql = "select password from acornuser.parents_space_pass where deviceNumber = '{}'".format(device_number) | ||
358 | result = db.select(sql) | ||
359 | if result: | ||
360 | return result[0]['password'] | ||
361 | else: | ||
362 | return '123456' | ||
363 | |||
364 | |||
365 | ## ********************************************************************************************************************* | ||
366 | ## 家长控制 app使用统计 | ||
367 | ## ********************************************************************************************************************* | ||
368 | # "now" format: timestamp , create app using data about this week, month, year, last year(according 'now' time) | ||
369 | def create_app_use_record(now, user_id, device_number): | ||
370 | today = date.fromtimestamp(now) | ||
371 | year_start_time = int(str(time.mktime(date(today.year, 1, 1).timetuple())).split('.')[0]) | ||
372 | where_equal = {'user_id':user_id, 'device_number':device_number} | ||
373 | where_unequal = ' time_end > {} '.format(year_start_time) | ||
374 | if db.select_('analytics.app_record', where_equal, where_unequal): # data existing | ||
375 | update_data = "update analytics.app_record set device_number = '{}' where user_id = '{}' and device_number = '{}' " \ | ||
376 | .format(str(time.time()), user_id, device_number) | ||
377 | db.update_(update_data) | ||
378 | study_apps = [{'app_name':'百度英语资料大全', 'app_pid':'com.sailang.EnglishBook','category_id':'25', 'source_id':'1', \ | ||
379 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
380 | {'app_name': '开心大学士', 'app_pid': 'com.ksense.study','category_id':'26', 'source_id':'1', \ | ||
381 | 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
382 | {'app_name': '驾考宝典', 'app_pid': 'com.handsgo.jiakao.android' ,'category_id':'27', 'source_id':'1', \ | ||
383 | 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
384 | {'app_name': '我爱汉字', 'app_pid': 'com.cronlygames.hanzi' ,'category_id':'28', 'source_id':'1',\ | ||
385 | 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
386 | {'app_name': '拖拖乐3', 'app_pid': 'cn.com.wiisoft.tuotuo' ,'category_id':'57', 'source_id':'1', \ | ||
387 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
388 | {'app_name': '幼儿数字算数学习', 'app_pid': 'com.syhrobert1991.infantlearning' ,'category_id':'25', \ | ||
389 | 'source_id':'1', 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
390 | {'app_name': '轻松背单词之初中英语', 'app_pid': 'petpestzx.wordroid.model' ,'category_id':'26', \ | ||
391 | 'source_id':'2', 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
392 | {'app_name': '有谱-爱学习(数理化)', 'app_pid': 'com.emingren.youpu' ,'category_id':'27', 'source_id':'2', \ | ||
393 | 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
394 | {'app_name': '疯狂音标', 'app_pid': 'com.neo.crazyphonetic' ,'category_id':'28', 'source_id':'2', \ | ||
395 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
396 | {'app_name': '互动作业V3.18.6', 'app_pid': 'com.v.study' ,'category_id':'57', 'source_id':'2', \ | ||
397 | 'time_spent': 250, 'user_id': user_id, 'device_number': device_number}, | ||
398 | {'app_name': '发音背单词', 'app_pid': 'org.liberty.android.fantastischmemo' ,'category_id':'57', \ | ||
399 | 'source_id':'2', 'time_spent': 350, 'user_id': user_id, 'device_number': device_number}, | ||
400 | {'app_name': '语文100', 'app_pid': 'com.kk.kkyuwen' ,'category_id':'57', 'source_id':'2', \ | ||
401 | 'time_spent': 450, 'user_id': user_id, 'device_number': device_number} | ||
402 | ] | ||
403 | |||
404 | game_apps = [{'app_name': '小伴龙新', 'app_pid': 'com.xiaobanlong.main' ,'category_id':'37', 'source_id':'1',\ | ||
405 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
406 | {'app_name': '三国群英传', 'app_pid': 'com.tencent.tmgp.sgqyz' ,'category_id':'38', 'source_id':'1', \ | ||
407 | 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
408 | {'app_name': '童言童语', 'app_pid': 'com.lingshi.kids' ,'category_id':'39', 'source_id':'2', \ | ||
409 | 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
410 | {'app_name': '从前啊', 'app_pid': 'com.mojie.longlongago' ,'category_id':'37', 'source_id':'2', \ | ||
411 | 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
412 | {'app_name': '永恒纪元', 'app_pid': 'com.m37.dtszj.uc' ,'category_id':'38', 'source_id':'2', \ | ||
413 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
414 | {'app_name': '我的世界新', 'app_pid': 'com.netease.mc.aligames' ,'category_id':'39', 'source_id':'2', \ | ||
415 | 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
416 | {'app_name': '球球大作战', 'app_pid': 'com.ztgame.bob', 'category_id': '37', 'source_id': '2', \ | ||
417 | 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
418 | {'app_name': '葫芦侠我的世界', 'app_pid': 'com.huluxia.mctool', 'category_id': '38', 'source_id': '2',\ | ||
419 | 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
420 | {'app_name': 'QQ游戏V6.8.7', 'app_pid': 'com.tencent.qqgame', 'category_id': '39', 'source_id': '2',\ | ||
421 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
422 | {'app_name': '99围棋最新', 'app_pid': 'com.r99weiqi.dvd', 'category_id': '37', 'source_id': '2', \ | ||
423 | 'time_spent': 50, 'user_id': user_id, 'device_number': device_number}, | ||
424 | {'app_name': '凯蒂环球之旅', 'app_pid': 'com.tencent.HelloKitty', 'category_id': '37', 'source_id': '2',\ | ||
425 | 'time_spent': 150, 'user_id': user_id, 'device_number': device_number}, | ||
426 | {'app_name': '贪吃蛇大作战', 'app_pid': 'com.wepie.snake.qihoo', 'category_id': '100', 'source_id': '2',\ | ||
427 | 'time_spent': 250, 'user_id': user_id, 'device_number': device_number} | ||
428 | ] | ||
429 | |||
430 | # get date of the last 7 days(include today) | ||
431 | days = [] # the day should insert app records | ||
432 | if today.month == 1: # the first month of this year | ||
433 | if today.day <= 7: # when today < 7th day of this month , 7 records chould cover this week ,this month, this year | ||
434 | for i in range(0, 7): | ||
435 | day_delta = timedelta(days=i) | ||
436 | days.append(str(time.mktime((today - day_delta).timetuple())).split('.')[0]) | ||
437 | else: # when today > 7th day of this month , should create 8 records to cover this week ,this month, this year | ||
438 | for i in range(0, 8): | ||
439 | day_delta = timedelta(days=i) | ||
440 | days.append(str(time.mktime((today - day_delta).timetuple())).split('.')[0]) | ||
441 | else: # create january data to cover this year | ||
442 | for i in range(0, 8): | ||
443 | day_delta = timedelta(days=i) | ||
444 | days.append(str(time.mktime((today - day_delta).timetuple())).split('.')[0]) | ||
445 | days.append(str(time.mktime(date(today.year, 1, 1).timetuple())).split('.')[0]) | ||
446 | |||
447 | |||
448 | app_rec_to_insert = [] | ||
449 | for day in days: | ||
450 | for i in range(0, 12): | ||
451 | time_end_1 = {'time_end': int(day) + 28800 + i * 1000, 'id':str(uuid.uuid4()).replace('-', '')} | ||
452 | time_end_2 = {'time_end': int(day) + 29800 + i * 500, 'id':str(uuid.uuid4()).replace('-', '')} | ||
453 | study_app = study_apps[i].copy() | ||
454 | study_app.update(time_end_1) | ||
455 | game_app = game_apps[i].copy() | ||
456 | game_app.update(time_end_2) | ||
457 | app_rec_to_insert.append(study_app) | ||
458 | app_rec_to_insert.append(game_app) | ||
459 | |||
460 | for rec in app_rec_to_insert: | ||
461 | db.insert('analytics.app_record', rec) | ||
462 | |||
463 | |||
464 | |||
465 | |||
466 | |||
467 | |||
468 | |||
469 | |||
470 | |||
471 | |||
472 | |||
473 | |||
474 | |||
475 | |||
476 | |||
477 | |||
478 | |||
479 | |||
480 | |||
481 | |||
482 | |||
483 | |||
484 | |||
485 |
data_fixture/mysql_db.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import configparser | ||
5 | import pymysql.cursors | ||
6 | import os | ||
7 | |||
8 | from . import config_data as Data | ||
9 | # | ||
10 | # base_dir = str(os.path.dirname(os.path.dirname(__file__))) | ||
11 | # config_dir = base_dir.replace('\\', '/') | ||
12 | # config_path = config_dir + '/config.ini' | ||
13 | # | ||
14 | # cp = configparser.ConfigParser() | ||
15 | # cp.read(config_path) | ||
16 | # DB_host = cp.get('mysqlconf', 'host') | ||
17 | # DB_port = cp.get('mysqlconf', 'port') | ||
18 | # DB_username = cp.get('mysqlconf', 'user') | ||
19 | # DB_password = cp.get('mysqlconf', 'password') | ||
20 | # DB_dbName = cp.get('mysqlconf', 'db_name') | ||
21 | |||
22 | |||
23 | class DB: | ||
24 | |||
25 | def __init__ (self): | ||
26 | try: | ||
27 | self.connection = pymysql.connect(host=Data.DB_HOST, | ||
28 | port=Data.DB_PORT, | ||
29 | user=Data.DB_USERNAME, | ||
30 | password=Data.DB_PASSWORD, | ||
31 | charset='utf8mb4', | ||
32 | cursorclass=pymysql.cursors.DictCursor | ||
33 | ) | ||
34 | except pymysql.err.OperationalError as e: | ||
35 | print ("MySql error %d: %s" % (e.args[0], e.args[1])) | ||
36 | |||
37 | def select(self, sql): | ||
38 | with self.connection.cursor() as cursor: | ||
39 | if cursor.execute(sql): | ||
40 | return cursor.fetchall() | ||
41 | else: | ||
42 | return None | ||
43 | |||
44 | def select_(self, tabel_name, where_data_equal, where_data_unequal = None ): | ||
45 | sql_where = ' and '.join("{} = '{}' ".format(key, value) for (key, value) in where_data_equal.items()) | ||
46 | if where_data_unequal: | ||
47 | sql_where = sql_where + ' and ' + where_data_unequal | ||
48 | sql = 'select count(1) from ' + tabel_name + ' where ' + sql_where | ||
49 | with self.connection.cursor() as cursor: | ||
50 | cursor.execute(sql) | ||
51 | result = cursor.fetchone() | ||
52 | return result['count(1)'] | ||
53 | |||
54 | |||
55 | def insert(self, table_name, table_data): | ||
56 | for key in table_data: | ||
57 | table_data[key] = " '" + str(table_data[key]) + "'" | ||
58 | key = ','.join(table_data.keys()) | ||
59 | value = ','.join(table_data.values()) | ||
60 | real_sql = 'INSERT INTO ' + table_name + " (" + key + " ) VALUES ( "\ | ||
61 | + value + " )" | ||
62 | with self.connection.cursor() as cursor: | ||
63 | cursor.execute(real_sql) | ||
64 | self.connection.commit() | ||
65 | |||
66 | def update(self, table_name, set_data, where_data): | ||
67 | sql_set = ','.join("{}='{}'".format(key, value) for (key, value) in set_data.items()) | ||
68 | sql_where = ' and '.join("{}='{}'".format(key, value) for (key, value) in where_data.items()) | ||
69 | print(sql_set, sql_where) | ||
70 | real_sql = "UPDATE " + table_name + " SET " + sql_set + " WHERE " + sql_where | ||
71 | |||
72 | with self.connection.cursor() as cursor: | ||
73 | cursor.execute(real_sql) | ||
74 | self.connection.commit() | ||
75 | |||
76 | |||
77 | def update_(self, sql): | ||
78 | with self.connection.cursor() as cursor: | ||
79 | cursor.execute(sql) | ||
80 | self.connection.commit() | ||
81 | |||
82 | |||
83 | def close(self): | ||
84 | self.connection.close() | ||
85 | |||
86 | |||
87 | |||
88 |
data_fixture/test_verify.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | from data_fixture.mysql_db import DB | ||
5 | from data_fixture import config_data as Data | ||
6 | from datetime import datetime | ||
7 | import time | ||
8 | from data_fixture.config_data import HOST_BOSS | ||
9 | import requests | ||
10 | |||
11 | |||
12 |
report/test_report.html
File was created | 1 | <?xml version="1.0" encoding="UTF-8"?> | |
2 | <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd"> | ||
3 | <html xmlns="http://www.w3.org/1999/xhtml"> | ||
4 | <head> | ||
5 | <title>Unit Test Report</title> | ||
6 | <meta name="generator" content="HTMLTestRunner 0.8.2"/> | ||
7 | <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/> | ||
8 | |||
9 | <style type="text/css" media="screen"> | ||
10 | body { font-family: verdana, arial, helvetica, sans-serif; font-size: 80%; } | ||
11 | table { font-size: 100%; } | ||
12 | pre { } | ||
13 | |||
14 | /* -- heading ---------------------------------------------------------------------- */ | ||
15 | h1 { | ||
16 | font-size: 16pt; | ||
17 | color: gray; | ||
18 | } | ||
19 | .heading { | ||
20 | margin-top: 0ex; | ||
21 | margin-bottom: 1ex; | ||
22 | } | ||
23 | |||
24 | .heading .attribute { | ||
25 | margin-top: 1ex; | ||
26 | margin-bottom: 0; | ||
27 | } | ||
28 | |||
29 | .heading .description { | ||
30 | margin-top: 4ex; | ||
31 | margin-bottom: 6ex; | ||
32 | } | ||
33 | |||
34 | /* -- css div popup ------------------------------------------------------------------------ */ | ||
35 | a.popup_link { | ||
36 | } | ||
37 | |||
38 | a.popup_link:hover { | ||
39 | color: red; | ||
40 | } | ||
41 | |||
42 | .popup_window { | ||
43 | display: none; | ||
44 | position: relative; | ||
45 | left: 0px; | ||
46 | top: 0px; | ||
47 | /*border: solid #627173 1px; */ | ||
48 | padding: 10px; | ||
49 | background-color: #E6E6D6; | ||
50 | font-family: "Lucida Console", "Courier New", Courier, monospace; | ||
51 | text-align: left; | ||
52 | font-size: 8pt; | ||
53 | width: 500px; | ||
54 | } | ||
55 | |||
56 | } | ||
57 | /* -- report ------------------------------------------------------------------------ */ | ||
58 | #show_detail_line { | ||
59 | margin-top: 3ex; | ||
60 | margin-bottom: 1ex; | ||
61 | } | ||
62 | #result_table { | ||
63 | width: 80%; | ||
64 | border-collapse: collapse; | ||
65 | border: 1px solid #777; | ||
66 | } | ||
67 | #header_row { | ||
68 | font-weight: bold; | ||
69 | color: white; | ||
70 | background-color: #777; | ||
71 | } | ||
72 | #result_table td { | ||
73 | border: 1px solid #777; | ||
74 | padding: 2px; | ||
75 | } | ||
76 | #total_row { font-weight: bold; } | ||
77 | .passClass { background-color: #6c6; } | ||
78 | .failClass { background-color: #c60; } | ||
79 | .errorClass { background-color: #c00; } | ||
80 | .passCase { color: #6c6; } | ||
81 | .failCase { color: #c60; font-weight: bold; } | ||
82 | .errorCase { color: #c00; font-weight: bold; } | ||
83 | .hiddenRow { display: none; } | ||
84 | .testcase { margin-left: 2em; } | ||
85 | |||
86 | |||
87 | /* -- ending ---------------------------------------------------------------------- */ | ||
88 | #ending { | ||
89 | } | ||
90 | |||
91 | </style> | ||
92 | |||
93 | </head> | ||
94 | <body> | ||
95 | <script language="javascript" type="text/javascript"><!-- | ||
96 | output_list = Array(); | ||
97 | |||
98 | /* level - 0:Summary; 1:Failed; 2:All */ | ||
99 | function showCase(level) { | ||
100 | trs = document.getElementsByTagName("tr"); | ||
101 | for (var i = 0; i < trs.length; i++) { | ||
102 | tr = trs[i]; | ||
103 | id = tr.id; | ||
104 | if (id.substr(0,2) == 'ft') { | ||
105 | if (level < 1) { | ||
106 | tr.className = 'hiddenRow'; | ||
107 | } | ||
108 | else { | ||
109 | tr.className = ''; | ||
110 | } | ||
111 | } | ||
112 | if (id.substr(0,2) == 'pt') { | ||
113 | if (level > 1) { | ||
114 | tr.className = ''; | ||
115 | } | ||
116 | else { | ||
117 | tr.className = 'hiddenRow'; | ||
118 | } | ||
119 | } | ||
120 | } | ||
121 | } | ||
122 | |||
123 | |||
124 | function showClassDetail(cid, count) { | ||
125 | var id_list = Array(count); | ||
126 | var toHide = 1; | ||
127 | for (var i = 0; i < count; i++) { | ||
128 | tid0 = 't' + cid.substr(1) + '.' + (i+1); | ||
129 | tid = 'f' + tid0; | ||
130 | tr = document.getElementById(tid); | ||
131 | if (!tr) { | ||
132 | tid = 'p' + tid0; | ||
133 | tr = document.getElementById(tid); | ||
134 | } | ||
135 | id_list[i] = tid; | ||
136 | if (tr.className) { | ||
137 | toHide = 0; | ||
138 | } | ||
139 | } | ||
140 | for (var i = 0; i < count; i++) { | ||
141 | tid = id_list[i]; | ||
142 | if (toHide) { | ||
143 | document.getElementById('div_'+tid).style.display = 'none' | ||
144 | document.getElementById(tid).className = 'hiddenRow'; | ||
145 | } | ||
146 | else { | ||
147 | document.getElementById(tid).className = ''; | ||
148 | } | ||
149 | } | ||
150 | } | ||
151 | |||
152 | |||
153 | function showTestDetail(div_id){ | ||
154 | var details_div = document.getElementById(div_id) | ||
155 | var displayState = details_div.style.display | ||
156 | // alert(displayState) | ||
157 | if (displayState != 'block' ) { | ||
158 | displayState = 'block' | ||
159 | details_div.style.display = 'block' | ||
160 | } | ||
161 | else { | ||
162 | details_div.style.display = 'none' | ||
163 | } | ||
164 | } | ||
165 | |||
166 | |||
167 | function html_escape(s) { | ||
168 | s = s.replace(/&/g,'&'); | ||
169 | s = s.replace(/</g,'<'); | ||
170 | s = s.replace(/>/g,'>'); | ||
171 | return s; | ||
172 | } | ||
173 | |||
174 | /* obsoleted by detail in <div> | ||
175 | function showOutput(id, name) { | ||
176 | var w = window.open("", //url | ||
177 | name, | ||
178 | "resizable,scrollbars,status,width=800,height=450"); | ||
179 | d = w.document; | ||
180 | d.write("<pre>"); | ||
181 | d.write(html_escape(output_list[id])); | ||
182 | d.write("\n"); | ||
183 | d.write("<a href='javascript:window.close()'>close</a>\n"); | ||
184 | d.write("</pre>\n"); | ||
185 | d.close(); | ||
186 | } | ||
187 | */ | ||
188 | --></script> | ||
189 | |||
190 | <div class='heading'> | ||
191 | <h1>Unit Test Report</h1> | ||
192 | <p class='attribute'><strong>Start Time:</strong> 2018-01-08 18:05:31</p> | ||
193 | <p class='attribute'><strong>Duration:</strong> 0:00:02.208474</p> | ||
194 | <p class='attribute'><strong>Status:</strong> Pass 6</p> | ||
195 | |||
196 | <p class='description'></p> | ||
197 | </div> | ||
198 | |||
199 | |||
200 | |||
201 | <p id='show_detail_line'>Show | ||
202 | <a href='javascript:showCase(0)'>Summary</a> | ||
203 | <a href='javascript:showCase(1)'>Failed</a> | ||
204 | <a href='javascript:showCase(2)'>All</a> | ||
205 | </p> | ||
206 | <table id='result_table'> | ||
207 | <colgroup> | ||
208 | <col align='left' /> | ||
209 | <col align='right' /> | ||
210 | <col align='right' /> | ||
211 | <col align='right' /> | ||
212 | <col align='right' /> | ||
213 | <col align='right' /> | ||
214 | </colgroup> | ||
215 | <tr id='header_row'> | ||
216 | <td>Test Group/Test case</td> | ||
217 | <td>Count</td> | ||
218 | <td>Pass</td> | ||
219 | <td>Fail</td> | ||
220 | <td>Error</td> | ||
221 | <td>View</td> | ||
222 | </tr> | ||
223 | |||
224 | <tr class='passClass'> | ||
225 | <td>subject_sync.ClassNameVideo</td> | ||
226 | <td>2</td> | ||
227 | <td>2</td> | ||
228 | <td>0</td> | ||
229 | <td>0</td> | ||
230 | <td><a href="javascript:showClassDetail('c1',2)">Detail</a></td> | ||
231 | </tr> | ||
232 | |||
233 | <tr id='pt1.1' class='hiddenRow'> | ||
234 | <td class='none'><div class='testcase'>test_ClassNameVideo_noData</div></td> | ||
235 | <td colspan='5' align='center'>pass</td> | ||
236 | </tr> | ||
237 | |||
238 | <tr id='pt1.2' class='hiddenRow'> | ||
239 | <td class='none'><div class='testcase'>test_ClassNameVideo_success</div></td> | ||
240 | <td colspan='5' align='center'>pass</td> | ||
241 | </tr> | ||
242 | |||
243 | <tr class='passClass'> | ||
244 | <td>subject_sync.ConsolidationExercise</td> | ||
245 | <td>1</td> | ||
246 | <td>1</td> | ||
247 | <td>0</td> | ||
248 | <td>0</td> | ||
249 | <td><a href="javascript:showClassDetail('c2',1)">Detail</a></td> | ||
250 | </tr> | ||
251 | |||
252 | <tr id='pt2.1' class='hiddenRow'> | ||
253 | <td class='none'><div class='testcase'>test_ConsolidationExercise_success</div></td> | ||
254 | <td colspan='5' align='center'>pass</td> | ||
255 | </tr> | ||
256 | |||
257 | <tr class='passClass'> | ||
258 | <td>subject_sync.PointVideo</td> | ||
259 | <td>2</td> | ||
260 | <td>2</td> | ||
261 | <td>0</td> | ||
262 | <td>0</td> | ||
263 | <td><a href="javascript:showClassDetail('c3',2)">Detail</a></td> | ||
264 | </tr> | ||
265 | |||
266 | <tr id='pt3.1' class='hiddenRow'> | ||
267 | <td class='none'><div class='testcase'>test_PointVideo_noData</div></td> | ||
268 | <td colspan='5' align='center'>pass</td> | ||
269 | </tr> | ||
270 | |||
271 | <tr id='pt3.2' class='hiddenRow'> | ||
272 | <td class='none'><div class='testcase'>test_PointVideo_success</div></td> | ||
273 | <td colspan='5' align='center'>pass</td> | ||
274 | </tr> | ||
275 | |||
276 | <tr class='passClass'> | ||
277 | <td>subject_sync.SubjectTest</td> | ||
278 | <td>1</td> | ||
279 | <td>1</td> | ||
280 | <td>0</td> | ||
281 | <td>0</td> | ||
282 | <td><a href="javascript:showClassDetail('c4',1)">Detail</a></td> | ||
283 | </tr> | ||
284 | |||
285 | <tr id='pt4.1' class='hiddenRow'> | ||
286 | <td class='none'><div class='testcase'>test_SubjectTest_success</div></td> | ||
287 | <td colspan='5' align='center'>pass</td> | ||
288 | </tr> | ||
289 | |||
290 | <tr id='total_row'> | ||
291 | <td>Total</td> | ||
292 | <td>6</td> | ||
293 | <td>6</td> | ||
294 | <td>0</td> | ||
295 | <td>0</td> | ||
296 | <td> </td> | ||
297 | </tr> | ||
298 | </table> | ||
299 | |||
300 | <div id='ending'> </div> | ||
301 | |||
302 | </body> | ||
303 | </html> | ||
304 |
run_test.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import HTMLTestRunner | ||
6 | from test_cases import sub_account | ||
7 | |||
8 | from test_suites import test_elecCard | ||
9 | from test_cases import register | ||
10 | from test_cases import personal_info | ||
11 | from test_cases import parent_space | ||
12 | from test_cases import app_record_statistic | ||
13 | from test_cases import subject_sync | ||
14 | |||
15 | start_dir = './test_cases' | ||
16 | suite_run = unittest.TestSuite() | ||
17 | suite_run = unittest.defaultTestLoader.discover(start_dir=start_dir, pattern='subject_sync.py') | ||
18 | |||
19 | |||
20 | #suite_run.addTest(app_record_statistic.AppRecordEveryday('test_getAppRecordEveryday_success')) | ||
21 | |||
22 | #suite_run.addTest(app_record_statistic.AppRecordReset('test_AppRecordReset_success')) | ||
23 | #suite_run.addTest(parent_space.ParentSpaceNewPassword('test_ParentSpaceNewPassword_success')) | ||
24 | #suite_run.addTest(parent_space.ParentSpaceNewPassword('test_ParentSpaceNewPassword_authCodeError')) | ||
25 | runner = HTMLTestRunner.HTMLTestRunner(outputdir='report') | ||
26 | |||
27 | if __name__ == '__main__': | ||
28 | |||
29 | runner.run(suite_run) | ||
30 | |||
31 | |||
32 |
run_test.pyc
No preview for this file type
test_cases/1.jpg
216 KB
test_cases/1.png
216 KB
test_cases/__pycache__/app_record_statistic.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/debugggggg.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/eleccard_check.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/eleccard_setUp.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/parent_space.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/personal_info.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/press.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/region_grade_school.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/register.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/sub_account.cpython-36.pyc
No preview for this file type
test_cases/__pycache__/subject_sync.cpython-36.pyc
No preview for this file type
test_cases/app_record_statistic.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS, HOST_STA | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | from data_fixture.mysql_db import DB | ||
10 | import time | ||
11 | from datetime import date | ||
12 | |||
13 | db_test = DB() | ||
14 | |||
15 | |||
16 | #提交app使用记录 | ||
17 | class AppRecordSave(unittest.TestCase): | ||
18 | def setUp(self): | ||
19 | self.base_url = HOST_STA + '/app/record/save' | ||
20 | |||
21 | def tearDown(self): | ||
22 | print(self.result) | ||
23 | |||
24 | def test_AppRecordSave_success(self): | ||
25 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
26 | postData = {'appName': '学科同步', | ||
27 | 'appPid': 'com.hjx.synsubject', | ||
28 | 'timeSpent': 1088, | ||
29 | 'userId': Data.USER_ID, | ||
30 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND} | ||
31 | send_time = str(time.time()).split('.')[0] | ||
32 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
33 | self.result = r.json() | ||
34 | self.assertEqual(self.result['status'], 1, 'test_AppRecordSave_success Error') | ||
35 | where = {'app_name': '学科同步', | ||
36 | 'app_pid': 'com.hjx.synsubject', | ||
37 | 'time_spent': 1088, | ||
38 | 'user_id': Data.USER_ID, | ||
39 | 'device_number': Data.DEVICE_NUMBER_CUS_BIND} | ||
40 | where_2 = " time_end >= {} ".format(send_time) | ||
41 | self.assertTrue(db_test.select_('analytics.app_record', where, where_2) >= 1, 'test_AppRecordSave_success data Error') | ||
42 | |||
43 | |||
44 | # 按时间段获取app使用统计 | ||
45 | class AppRecordStats(unittest.TestCase): | ||
46 | def setUp(self): | ||
47 | self.base_url = HOST_STA + '/app/record/stats' | ||
48 | now = int(str(time.time()).split('.')[0]) | ||
49 | CreateTestData.create_app_use_record(now, Data.USER_ID, Data.DEVICE_NUMBER_CUS_BIND) | ||
50 | |||
51 | def tearDown(self): | ||
52 | pass | ||
53 | |||
54 | def test_getAppRecordStats_all_success(self): | ||
55 | getData = {'userId': Data.USER_ID, | ||
56 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
57 | 'type': 'all'} | ||
58 | r = requests.get(self.base_url, params=getData) | ||
59 | self.result_1 = r.json() | ||
60 | self.assertEqual(self.result_1['status'], 1, 'test_getAppRecordStats_all_success Error') | ||
61 | self.assertTrue(self.result_1['data']['gameTime'] > 0) | ||
62 | self.assertTrue(self.result_1['data']['studyTime'] > 0) | ||
63 | |||
64 | def test_getAppRecordStats_year_success(self): | ||
65 | getData = {'userId': Data.USER_ID, | ||
66 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
67 | 'type': 'year'} | ||
68 | r = requests.get(self.base_url, params=getData) | ||
69 | self.result_2 = r.json() | ||
70 | self.assertEqual(self.result_2['status'], 1, 'test_getAppRecordStats_year_success Error') | ||
71 | self.assertTrue(self.result_2['data']['gameTime'] > 0) | ||
72 | self.assertTrue(self.result_2['data']['studyTime'] > 0) | ||
73 | |||
74 | def test_getAppRecordStats_month_success(self): | ||
75 | getData = {'userId': Data.USER_ID, | ||
76 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
77 | 'type': 'month'} | ||
78 | r = requests.get(self.base_url, params=getData) | ||
79 | self.result_3 = r.json() | ||
80 | self.assertEqual(self.result_3['status'], 1, 'test_getAppRecordStats_month_success Error') | ||
81 | self.assertTrue(self.result_3['data']['gameTime'] > 0) | ||
82 | self.assertTrue(self.result_3['data']['studyTime'] > 0) | ||
83 | |||
84 | def test_getAppRecordStats_week_success(self): | ||
85 | getData = {'userId': Data.USER_ID, | ||
86 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
87 | 'type': 'week'} | ||
88 | r = requests.get(self.base_url, params=getData) | ||
89 | self.result_4 = r.json() | ||
90 | self.assertEqual(self.result_4['status'], 1, 'test_getAppRecordStats_week_success Error') | ||
91 | self.assertTrue(self.result_4['data']['gameTime'] > 0) | ||
92 | self.assertTrue(self.result_4['data']['studyTime'] > 0) | ||
93 | |||
94 | |||
95 | # 获取应用统计top排名 | ||
96 | class AppRecordTop(unittest.TestCase): | ||
97 | def setUp(self): | ||
98 | self.base_url = HOST_STA + '/app/record/top' | ||
99 | now = int(str(time.time()).split('.')[0]) | ||
100 | CreateTestData.create_app_use_record(now, Data.USER_ID, Data.DEVICE_NUMBER_CUS_BIND) | ||
101 | |||
102 | def tearDown(self): | ||
103 | pass | ||
104 | |||
105 | def test_getAppRecordTop_hjx(self): | ||
106 | getData = {'userId': Data.USER_ID, | ||
107 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
108 | 'type': 'hjx'} | ||
109 | r = requests.get(self.base_url, params=getData) | ||
110 | self.result_1 = r.json() | ||
111 | self.assertEqual(self.result_1['status'], 1, 'test_getAppRecordTop_hjx Error') | ||
112 | self.assertTrue(len(self.result_1['data']) > 0) | ||
113 | |||
114 | def test_getAppRecordTop_other(self): | ||
115 | getData = {'userId': Data.USER_ID, | ||
116 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
117 | 'type': 'other'} | ||
118 | r = requests.get(self.base_url, params=getData) | ||
119 | self.result_2 = r.json() | ||
120 | self.assertEqual(self.result_2['status'], 1, 'test_getAppRecordTop_other Error') | ||
121 | self.assertTrue(len(self.result_2['data']) > 0) | ||
122 | |||
123 | |||
124 | # 获取某一天的app统计 | ||
125 | class AppRecordOneday(unittest.TestCase): | ||
126 | def setUp(self): | ||
127 | self.base_url = HOST_STA + '/app/record/oneday' | ||
128 | self.now = int(str(time.time()).split('.')[0]) | ||
129 | CreateTestData.create_app_use_record(self.now, Data.USER_ID, Data.DEVICE_NUMBER_CUS_BIND) | ||
130 | |||
131 | def tearDown(self): | ||
132 | pass | ||
133 | |||
134 | def test_getAppRecordOneday_success(self): | ||
135 | getData = {'userId': Data.USER_ID, | ||
136 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
137 | 'dayTimestamp': str(time.mktime(date.today().timetuple())).split('.')[0]} | ||
138 | pageNum = 1 | ||
139 | appRecord = [] | ||
140 | while True: | ||
141 | getData.update({'pageNum':pageNum}) | ||
142 | r = requests.get(self.base_url, params=getData) | ||
143 | self.result = r.json() | ||
144 | appRecord = appRecord + self.result['data'] | ||
145 | if len(self.result['data']) == 0: | ||
146 | break | ||
147 | pageNum += 1 | ||
148 | |||
149 | self.result_1 = r.json() | ||
150 | self.assertTrue(len(appRecord) == 24) | ||
151 | |||
152 | app_name = appRecord[0]['appName'] | ||
153 | time_spent = appRecord[0]['timeSpentTotal'] | ||
154 | time_end = appRecord[0]['latestTimeEnd'] | ||
155 | source_id = appRecord[0]['sourceId'] | ||
156 | category_id = appRecord[0]['categoryId'] | ||
157 | categoryType = appRecord[0]['categoryType'] | ||
158 | study_category = [25,26,27,28,57] | ||
159 | game_category = [37,38,39,100] | ||
160 | |||
161 | where_1 = {'app_name':app_name, | ||
162 | 'time_spent':time_spent, | ||
163 | 'time_end': time_end, | ||
164 | 'source_id':source_id, | ||
165 | 'category_id':category_id, | ||
166 | 'user_id': Data.USER_ID, | ||
167 | 'device_number': Data.DEVICE_NUMBER_CUS_BIND | ||
168 | } | ||
169 | self.assertEqual(db_test.select_('analytics.app_record', where_1) , 1) | ||
170 | if category_id in study_category: | ||
171 | self.assertEqual(categoryType, 1) | ||
172 | if category_id in game_category: | ||
173 | self.assertEqual(categoryType, 2) | ||
174 | |||
175 | |||
176 | # 获取几天的app统计 | ||
177 | class AppRecordEveryday(unittest.TestCase): | ||
178 | def setUp(self): | ||
179 | self.base_url = HOST_STA + '/app/record/everyday' | ||
180 | self.now = int(str(time.time()).split('.')[0]) | ||
181 | # CreateTestData.create_app_use_record(self.now, Data.USER_ID, Data.DEVICE_NUMBER_CUS_BIND) | ||
182 | CreateTestData.create_app_use_record(self.now, '7000000054686780', '123456789002') | ||
183 | |||
184 | |||
185 | def tearDown(self): | ||
186 | pass | ||
187 | |||
188 | def test_getAppRecordEveryday_success(self): | ||
189 | # getData = {'userId': Data.USER_ID, | ||
190 | # 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
191 | # 'pageNum': 1, | ||
192 | # 'pageSize': 7} | ||
193 | getData = {'userId': '7000000054686780', | ||
194 | 'deviceNumber': '123456789002', | ||
195 | 'pageNum': 1, | ||
196 | 'pageSize': 7} | ||
197 | r = requests.get(self.base_url, params=getData) | ||
198 | self.result = r.json() | ||
199 | self.assertEqual(self.result['status'], 1, 'test_getAppRecordEveryday_success Error') | ||
200 | self.assertEqual(self.result['data'][0]['gameTimeSpent'], 2550) | ||
201 | self.assertEqual(self.result['data'][0]['studyTimeSpent'], 3150) | ||
202 | |||
203 | |||
204 | # 获取当天的app统计 | ||
205 | class AppRecordToday(unittest.TestCase): | ||
206 | def setUp(self): | ||
207 | self.base_url = HOST_STA + '/app/record/today' | ||
208 | self.now = int(str(time.time()).split('.')[0]) | ||
209 | CreateTestData.create_app_use_record(self.now, Data.USER_ID, Data.DEVICE_NUMBER_CUS_BIND) | ||
210 | |||
211 | def tearDown(self): | ||
212 | pass | ||
213 | |||
214 | def test_AppRecordToday_success(self): | ||
215 | getData = {'userId': Data.USER_ID, | ||
216 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND} | ||
217 | r = requests.get(self.base_url, params=getData) | ||
218 | self.result = r.json() | ||
219 | self.assertEqual(self.result['status'], 1, 'AppRecordToday Error') | ||
220 | self.assertEqual(self.result['data']['gameTimeSpent'], 2550) | ||
221 | self.assertEqual(self.result['data']['studyTimeSpent'], 3150) | ||
222 | |||
223 | |||
224 | #重置数据接口 | ||
225 | class AppRecordReset(unittest.TestCase): | ||
226 | def setUp(self): | ||
227 | self.base_url = HOST_STA + '/app/record/reset' | ||
228 | # create elec card , to get mobile phpne | ||
229 | self.password = CreateTestData.get_parentSpace_password(Data.DEVICE_NUMBER_CUS_BIND) | ||
230 | now = int(str(time.time()).split('.')[0]) | ||
231 | CreateTestData.create_app_use_record(now, Data.USER_ID, Data.DEVICE_NUMBER_CUS_BIND) | ||
232 | |||
233 | def tearDown(self): | ||
234 | pass | ||
235 | |||
236 | def test_AppRecordReset_success(self): | ||
237 | getData = {'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
238 | 'password': self.password, | ||
239 | 'userId': Data.USER_ID | ||
240 | } | ||
241 | r = requests.post(self.base_url, data=getData) | ||
242 | self.result = r.json() | ||
243 | self.assertEqual(self.result['status'], 1, 'test_AppRecordReset_success Error') | ||
244 | where = {'device_number': Data.DEVICE_NUMBER_CUS_BIND, | ||
245 | 'user_id': Data.USER_ID | ||
246 | } | ||
247 | self.assertEqual(db_test.select_('analytics.app_record', where), 0) | ||
248 | |||
249 | def test_AppRecordReset_passwordError(self): | ||
250 | getData = {'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
251 | 'userId': Data.USER_ID, | ||
252 | 'password': self.password + '111' | ||
253 | } | ||
254 | r = requests.post(self.base_url, data=getData) | ||
255 | self.result_2 = r.json() | ||
256 | self.assertEqual(self.result_2['status'], 1005, 'test_AppRecordReset_passwordError Error') | ||
257 | |||
258 | |||
259 | |||
260 |
test_cases/debugggggg.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import uuid | ||
5 | |||
6 | def create_app_use_record(user_id, device_number): | ||
7 | |||
8 | study_apps = [{'app_name':"百度英语资料大全", 'app_pid':'com.sailang.EnglishBook','category_id':'25', \ | ||
9 | 'source_id':'1','time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
10 | {'app_name': '开心大学士', 'app_pid': 'com.ksense.study','category_id':'26', 'source_id':'1', \ | ||
11 | 'time_spent': 200, }, | ||
12 | {'app_name': '驾考宝典', 'app_pid': 'com.handsgo.jiakao.android' ,'category_id':'27', 'source_id':'1', \ | ||
13 | 'time_spent': 300 }, | ||
14 | {'app_name': '我爱汉字', 'app_pid': 'com.cronlygames.hanzi' ,'category_id':'28', 'source_id':'1',\ | ||
15 | 'time_spent': 400}, | ||
16 | {'app_name': '拖拖乐3', 'app_pid': 'cn.com.wiisoft.tuotuo' ,'category_id':'57', 'source_id':'1', \ | ||
17 | 'time_spent': 100}] | ||
18 | |||
19 | for j in range(0,2): | ||
20 | for i in range(0, 2): | ||
21 | time_end_1 = {'time_end': 28800 + i * 1000, 'id':str(uuid.uuid4()).replace('-', '')} | ||
22 | study_app = study_apps[i] | ||
23 | study_app.update(time_end_1) | ||
24 | mm = study_app | ||
25 | ll = len(study_app['app_name']) | ||
26 | ss = study_app['app_name'] | ||
27 | |||
28 | |||
29 | ################################################ | ||
30 | |||
31 | def create_app_use_record_2(user_id, device_number): | ||
32 | study_apps = [{'app_name':'百度英语资料大全', 'app_pid':'com.sailang.EnglishBook','category_id':'25', 'source_id':'1', \ | ||
33 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number} | ||
34 | # {'app_name': '开心大学士', 'app_pid': 'com.ksense.study','category_id':'26', 'source_id':'1', \ | ||
35 | # 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
36 | # {'app_name': '驾考宝典', 'app_pid': 'com.handsgo.jiakao.android' ,'category_id':'27', 'source_id':'1', \ | ||
37 | # 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
38 | # {'app_name': '我爱汉字', 'app_pid': 'com.cronlygames.hanzi' ,'category_id':'28', 'source_id':'1',\ | ||
39 | # 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
40 | # {'app_name': '拖拖乐3', 'app_pid': 'cn.com.wiisoft.tuotuo' ,'category_id':'57', 'source_id':'1', \ | ||
41 | # 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
42 | # {'app_name': '幼儿数字算数学习', 'app_pid': 'com.syhrobert1991.infantlearning' ,'category_id':'25', \ | ||
43 | # 'source_id':'1', 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
44 | # {'app_name': '轻松背单词之初中英语', 'app_pid': 'petpestzx.wordroid.model' ,'category_id':'26', \ | ||
45 | # 'source_id':'2', 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
46 | # {'app_name': '有谱-爱学习(数理化)', 'app_pid': 'com.emingren.youpu' ,'category_id':'27', 'source_id':'2', \ | ||
47 | # 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
48 | # {'app_name': '疯狂音标', 'app_pid': 'com.neo.crazyphonetic' ,'category_id':'28', 'source_id':'2', \ | ||
49 | # 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
50 | # {'app_name': '互动作业V3.18.6', 'app_pid': 'com.v.study' ,'category_id':'57', 'source_id':'2', \ | ||
51 | # 'time_spent': 250, 'user_id': user_id, 'device_number': device_number}, | ||
52 | # {'app_name': '发音背单词', 'app_pid': 'org.liberty.android.fantastischmemo' ,'category_id':'57', \ | ||
53 | # 'source_id':'2', 'time_spent': 350, 'user_id': user_id, 'device_number': device_number}, | ||
54 | # {'app_name': '语文100', 'app_pid': 'com.kk.kkyuwen' ,'category_id':'57', 'source_id':'2', \ | ||
55 | # 'time_spent': 450, 'user_id': user_id, 'device_number': device_number} | ||
56 | ] | ||
57 | |||
58 | game_apps = [{'app_name': '小伴龙新', 'app_pid': 'com.xiaobanlong.main' ,'category_id':'37', 'source_id':'1',\ | ||
59 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
60 | {'app_name': '三国群英传', 'app_pid': 'com.tencent.tmgp.sgqyz' ,'category_id':'38', 'source_id':'1', \ | ||
61 | 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
62 | {'app_name': '童言童语', 'app_pid': 'com.lingshi.kids' ,'category_id':'39', 'source_id':'2', \ | ||
63 | 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
64 | {'app_name': '从前啊', 'app_pid': 'com.mojie.longlongago' ,'category_id':'37', 'source_id':'2', \ | ||
65 | 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
66 | {'app_name': '永恒纪元', 'app_pid': 'com.m37.dtszj.uc' ,'category_id':'38', 'source_id':'2', \ | ||
67 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
68 | {'app_name': '我的世界新', 'app_pid': 'com.netease.mc.aligames' ,'category_id':'39', 'source_id':'2', \ | ||
69 | 'time_spent': 200, 'user_id': user_id, 'device_number': device_number}, | ||
70 | {'app_name': '球球大作战', 'app_pid': 'com.ztgame.bob', 'category_id': '37', 'source_id': '2', \ | ||
71 | 'time_spent': 300, 'user_id': user_id, 'device_number': device_number}, | ||
72 | {'app_name': '葫芦侠我的世界', 'app_pid': 'com.huluxia.mctool', 'category_id': '38', 'source_id': '2',\ | ||
73 | 'time_spent': 400, 'user_id': user_id, 'device_number': device_number}, | ||
74 | {'app_name': 'QQ游戏V6.8.7', 'app_pid': 'com.tencent.qqgame', 'category_id': '39', 'source_id': '2',\ | ||
75 | 'time_spent': 100, 'user_id': user_id, 'device_number': device_number}, | ||
76 | {'app_name': '99围棋最新', 'app_pid': 'com.r99weiqi.dvd', 'category_id': '37', 'source_id': '2', \ | ||
77 | 'time_spent': 50, 'user_id': user_id, 'device_number': device_number}, | ||
78 | {'app_name': '凯蒂环球之旅', 'app_pid': 'com.tencent.HelloKitty', 'category_id': '37', 'source_id': '2',\ | ||
79 | 'time_spent': 150, 'user_id': user_id, 'device_number': device_number}, | ||
80 | {'app_name': '贪吃蛇大作战', 'app_pid': 'com.wepie.snake.qihoo', 'category_id': '100', 'source_id': '2',\ | ||
81 | 'time_spent': 250, 'user_id': user_id, 'device_number': device_number} | ||
82 | ] | ||
83 | |||
84 | # get date of the last 7 days(include today) | ||
85 | days = ['111111','222222','333333'] # the day should insert app records | ||
86 | |||
87 | for day in days: | ||
88 | for i in range(0, 12): | ||
89 | time_end_1 = {'time_end': int(day) + 28800 + i * 1000, 'id':str(uuid.uuid4()).replace('-', '')} | ||
90 | time_end_2 = {'time_end': int(day) + 29800 + i * 500, 'id':str(uuid.uuid4()).replace('-', '')} | ||
91 | #study_apps[i].update(time_end_1) | ||
92 | #game_apps[i].update(time_end_2) | ||
93 | study_app = study_apps[0] | ||
94 | study_app.update(time_end_1) | ||
95 | ll = len(study_app['app_name']) | ||
96 | ss = study_app['app_name'] | ||
97 | game_app = game_apps[i] | ||
98 | game_app.update(time_end_2) | ||
99 | #db.insert('analytics.app_record_copy', study_app) | ||
100 | # db.insert('analytics.app_record_copy', game_app) | ||
101 | |||
102 | |||
103 | if __name__ == '__main__': | ||
104 | create_app_use_record_2('556600', 'HJKKJ1223123') | ||
105 | |||
106 | |||
107 | |||
108 | |||
109 | |||
110 | |||
111 | |||
112 | |||
113 | |||
114 | |||
115 | |||
116 | |||
117 | |||
118 | |||
119 |
test_cases/eleccard_check.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import logging | ||
5 | import unittest | ||
6 | import requests | ||
7 | from data_fixture.config_data import HOST_BOSS | ||
8 | from data_fixture import create_testdata as CreateTestData | ||
9 | from data_fixture import config_data as Data | ||
10 | |||
11 | |||
12 | #检查是否需要绑定保卡 | ||
13 | class CheckElecCardBind(unittest.TestCase): | ||
14 | def setUp(self): | ||
15 | self.base_url = HOST_BOSS + "/electronicCard/check" | ||
16 | CreateTestData.pre_elecCard(Data.DEVICE_NUMBER_CUS_BIND, Data.DEVICE_NUMBER_SAM, Data.DEVICE_NUMBER_CUS_UNBIND) | ||
17 | |||
18 | def tearDown(self): | ||
19 | print(self.result) | ||
20 | |||
21 | # 已绑定 -- 客机 | ||
22 | def test_checkElecCard_customerMachine(self): | ||
23 | headers = {'Accept': '*/*'} | ||
24 | getData = {'deviceNumber':Data.DEVICE_NUMBER_CUS_BIND} | ||
25 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
26 | self.result = r.json() | ||
27 | self.assertEqual(self.result['status'], 1, 'checkElecCard_customerMachine Error') | ||
28 | |||
29 | # 样机 | ||
30 | def test_checkElecCard_sampleMachine(self): | ||
31 | headers = {'Accept': '*/*'} | ||
32 | getData = {'deviceNumber': Data.DEVICE_NUMBER_SAM} | ||
33 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
34 | self.result = r.json() | ||
35 | self.assertEqual(self.result['status'], 2002, 'checkElecCard_sampleMachine Error') | ||
36 | |||
37 | # 未绑定 -- 客机 | ||
38 | def test_checkElecCard_unbind(self): | ||
39 | headers = {'Accept': '*/*'} | ||
40 | getData = {'deviceNumber': Data.DEVICE_NUMBER_CUS_UNBIND} | ||
41 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
42 | self.result = r.json() | ||
43 | self.assertEqual(self.result['status'], 2001, 'checkElecCard_unbind Error') | ||
44 | |||
45 | |||
46 | #获取保卡信息 | ||
47 | class GetCardInfo(unittest.TestCase): | ||
48 | def setUp(self): | ||
49 | self.base_url = HOST_BOSS + "/electronicCard/info" | ||
50 | CreateTestData.pre_elecCard(Data.DEVICE_NUMBER_CUS_BIND) | ||
51 | |||
52 | def tearDown(self): | ||
53 | print(self.result) | ||
54 | |||
55 | def test_getCardInfo_success(self): | ||
56 | headers = {'Accept': '*/*'} | ||
57 | getData = {'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND} | ||
58 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
59 | self.result = r.json() | ||
60 | self.assertEqual(self.result['status'], 1, 'getCardInfo Error') | ||
61 |
test_cases/eleccard_setUp.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS, HOST_ADMIN | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | |||
10 | |||
11 | #添加客机保卡 | ||
12 | class SetUpElecCard(unittest.TestCase): | ||
13 | def setUp(self): | ||
14 | self.base_url = HOST_BOSS + "/electronicCard/addCustomer" | ||
15 | CreateTestData.pre_SetUpElecCard() | ||
16 | def tearDown(self): | ||
17 | print(self.result) | ||
18 | |||
19 | def test_addElecCard_success(self): | ||
20 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
21 | postData = {'userId':Data.USER_ID, | ||
22 | 'customerName':'customer测试', | ||
23 | 'customerAddress':'田林路487号', | ||
24 | 'buyAddress':'虹梅路888号', | ||
25 | 'buyTime':'2017-12-02', | ||
26 | 'alterSaleCall':'55558888', | ||
27 | 'productModel':'TEST', | ||
28 | 'deviceNumber': Data.DEVICE_NUMBER_NEW, | ||
29 | 'macAddress':Data.MAC_NEW, | ||
30 | 'customerPhone':Data.USER_PHONE | ||
31 | } | ||
32 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
33 | self.result = r.json() | ||
34 | self.assertEqual(self.result['status'], 1, 'addElecCard Error') | ||
35 | |||
36 | |||
37 | # 置为样机,提交终端信息 | ||
38 | class SetToSample(unittest.TestCase): | ||
39 | |||
40 | def setUp(self): | ||
41 | self.base_url = HOST_ADMIN + "/admin/elecCard/updateToSample" | ||
42 | CreateTestData.pre_elecCard(device_cus_bind=Data.DEVICE_NUMBER_TO_SAM) | ||
43 | |||
44 | def tearDown(self): | ||
45 | pass | ||
46 | |||
47 | def test_updateToSample_success(self): | ||
48 | headers = {'Content-Type': 'multipart/form-data', 'Accept': 'application/json'} | ||
49 | postData = {'userId':Data.USER_ID, | ||
50 | 'deviceNumber':Data.DEVICE_NUMBER_TO_SAM, | ||
51 | 'terminalAddress':'terminalAddress终端地址', | ||
52 | 'distributor':'distributor经销商', | ||
53 | 'saleClerk':'saleClerk销售员', | ||
54 | 'mobilePhone':'18944444444' | ||
55 | } | ||
56 | files = {'photo':('252ED989-0B16-4AB7-81C1-974ABCF6CA11.png','image/png')} | ||
57 | r = requests.post(self.base_url, headers=headers, files=files, data=postData, allow_redirects=False) | ||
58 | self.assertEqual(r.status_code, 302, 'updateToSampleError') | ||
59 | |||
60 | |||
61 | #置为客机 | ||
62 | class SetToCustomer(unittest.TestCase): | ||
63 | |||
64 | def setUp(self): | ||
65 | self.base_url = HOST_ADMIN + "/admin/elecCard/updateToCustomer" | ||
66 | CreateTestData.pre_elecCard(device_sam=Data.DEVICE_NUMBER_TO_CUS) | ||
67 | |||
68 | def tearDown(self): | ||
69 | pass | ||
70 | |||
71 | def test_updateToCustomer_success(self): | ||
72 | headers = {'Accept': 'application/json'} | ||
73 | getData = {'userId': Data.USER_ID, 'deviceNumber': Data.DEVICE_NUMBER_TO_CUS} | ||
74 | r = requests.get(self.base_url, data=getData, allow_redirects=False) | ||
75 | self.assertEqual(r.status_code, 302, 'updateToCustomerError') | ||
76 | |||
77 | |||
78 | #解绑保卡 | ||
79 | class Unbind(unittest.TestCase): | ||
80 | def setUp(self): | ||
81 | self.base_url = HOST_ADMIN + "/admin/elecCard/delete" | ||
82 | CreateTestData.pre_elecCard(device_cus_bind=Data.DEVICE_NUMBER_UNBIND) | ||
83 | |||
84 | def tearDown(self): | ||
85 | pass | ||
86 | |||
87 | def test_unbindCard_success(self): | ||
88 | headers = {'Accept': '*/*'} | ||
89 | getData = {'deviceNumber': Data.DEVICE_NUMBER_UNBIND} | ||
90 | r = requests.get(self.base_url, headers=headers, data=getData, allow_redirects=False) | ||
91 | # self.result = r.json() | ||
92 | self.assertEqual(r.status_code, 302, 'unbindCardError') | ||
93 | |||
94 | |||
95 | #修改保卡 | ||
96 | class Card_Modify(unittest.TestCase): | ||
97 | def setUp(self): | ||
98 | self.base_url = HOST_BOSS + "/electronicCard/updateByUserId" | ||
99 | CreateTestData.pre_elecCard(device_cus_bind=Data.DEVICE_NUMBER_EDIT) | ||
100 | self.authCode = CreateTestData.fet_authCode(Data.USER_PHONE_EDIT) | ||
101 | |||
102 | def tearDown(self): | ||
103 | print(self.result) | ||
104 | |||
105 | def test_modifyCardInfo_phone_success(self): | ||
106 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
107 | postData = { | ||
108 | 'customerPhone':Data.USER_PHONE_EDIT, | ||
109 | 'authCode':self.authCode, | ||
110 | 'deviceNumber': Data.DEVICE_NUMBER_EDIT | ||
111 | } | ||
112 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
113 | self.result = r.json() | ||
114 | self.assertEqual(self.result['status'], 1, 'elecCardModifyError') | ||
115 | |||
116 | def test_modifyCardInfo_address_success(self): | ||
117 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
118 | postData = { | ||
119 | 'deviceNumber': Data.DEVICE_NUMBER_EDIT, | ||
120 | 'customerAddress': '上海徐汇区田林路888号修改', | ||
121 | 'customerPhone': Data.USER_PHONE_EDIT, | ||
122 | 'authCode':self.authCode | ||
123 | } | ||
124 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
125 | self.result = r.json() | ||
126 | self.assertEqual(self.result['status'], 1, 'elecCardModifyError') | ||
127 | |||
128 | |||
129 |
test_cases/parent_space.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS, HOST_STA | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | from data_fixture.mysql_db import DB | ||
10 | import uuid | ||
11 | import time | ||
12 | |||
13 | |||
14 | db_test = DB() | ||
15 | |||
16 | # 家长控制登录 | ||
17 | class ParentSpaceLogin(unittest.TestCase): | ||
18 | def setUp(self): | ||
19 | self.base_url = HOST_BOSS + '/parentsSpacePass/login' | ||
20 | self.password = CreateTestData.get_parentSpace_password(Data.DEVICE_NUMBER_CUS_BIND) | ||
21 | |||
22 | def tearDown(self): | ||
23 | print(self.result) | ||
24 | |||
25 | def test_ParentSpaceLogin_success(self): | ||
26 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
27 | postData = {'password': self.password, | ||
28 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
29 | } | ||
30 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
31 | self.result = r.json() | ||
32 | self.assertEqual(self.result['status'], 1, 'ParentSpaceLogin Error') | ||
33 | |||
34 | def test_ParentSpaceLogin_WrongPassword(self): | ||
35 | password_wrong = self.password + '11' | ||
36 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
37 | postData = {'password': password_wrong, | ||
38 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
39 | } | ||
40 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
41 | self.result = r.json() | ||
42 | self.assertEqual(self.result['status'], 1005, 'test_ParentSpaceLogin_WrongPassword Error') | ||
43 | |||
44 | |||
45 | # 家长控制修改密码 | ||
46 | class ParentSpaceChangePassword(unittest.TestCase): | ||
47 | def setUp(self): | ||
48 | self.base_url = HOST_BOSS + '/parentsSpacePass/changePassword' | ||
49 | self.oldPass = CreateTestData.get_parentSpace_password(Data.DEVICE_NUMBER_CUS_BIND) | ||
50 | |||
51 | def tearDown(self): | ||
52 | print(self.result) | ||
53 | |||
54 | def test_ParentSpaceChangePassword_success(self): | ||
55 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
56 | postData = {'oldPass': self.oldPass, | ||
57 | 'newPass': '111111', | ||
58 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
59 | } | ||
60 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
61 | self.result = r.json() | ||
62 | self.assertEqual(self.result['status'], 1, 'ParentSpacehangePassword Error') | ||
63 | where = {'password': '111111', | ||
64 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND } | ||
65 | self.assertEqual(db_test.select_('acornuser.parents_space_pass', where), 1, 'ParentSpacehangePassword data Error') | ||
66 | |||
67 | |||
68 | #家长控制忘记密码 | ||
69 | class ParentSpaceNewPassword(unittest.TestCase): | ||
70 | def setUp(self): | ||
71 | self.base_url = HOST_BOSS + '/parentsSpacePass/newpassword' | ||
72 | CreateTestData.pre_elecCard(Data.DEVICE_NUMBER_CUS_BIND) | ||
73 | sql = "SELECT customerPhone FROM acornuser.ozing_customermachine where deviceNumber = '{}'".format(Data.DEVICE_NUMBER_CUS_BIND) | ||
74 | self.mobile = db_test.select(sql)[0]["customerPhone"].strip() | ||
75 | self.auth = CreateTestData.fet_authCode(self.mobile) | ||
76 | |||
77 | def tearDown(self): | ||
78 | pass | ||
79 | |||
80 | def test_ParentSpaceNewPassword_success(self): | ||
81 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
82 | postData = {'userName': self.mobile, | ||
83 | 'authCode': self.auth, | ||
84 | 'password': '111111', | ||
85 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
86 | } | ||
87 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
88 | self.result = r.json() | ||
89 | self.assertEqual(self.result['status'], 1, 'test_ParentSpaceNewPassword_success Error') | ||
90 | where = {'password': '111111', | ||
91 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND } | ||
92 | self.assertEqual(db_test.select_('acornuser.parents_space_pass', where), 1, 'ParentSpacehangePassword data Error') | ||
93 | |||
94 | def test_ParentSpaceNewPassword_authCodeError(self): | ||
95 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
96 | postData = {'userName': self.mobile, | ||
97 | 'authCode': str(int(self.auth) - 1), | ||
98 | 'password': '111111', | ||
99 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND | ||
100 | } | ||
101 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
102 | self.result_2 = r.json() | ||
103 | self.assertEqual(self.result_2['status'], 1001, 'test_ParentSpaceNewPassword_success Error') | ||
104 | |||
105 | |||
106 | |||
107 |
test_cases/personal_info.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS | ||
7 | from data_fixture import config_data as Data | ||
8 | from data_fixture import create_testdata | ||
9 | from data_fixture.mysql_db import DB | ||
10 | import os | ||
11 | import uuid | ||
12 | |||
13 | db_test = DB() | ||
14 | current_dir = str(os.path.dirname(__file__)) | ||
15 | |||
16 | #获取个人信息 | ||
17 | class GetPersonalInfo(unittest.TestCase): | ||
18 | def setUp(self): | ||
19 | self.base_url = HOST_BOSS + "/personal/get" | ||
20 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
21 | create_testdata.pre_subAccount(Data.USER_ID, self.subAccount, 1) | ||
22 | |||
23 | def tearDown(self): | ||
24 | pass | ||
25 | |||
26 | def test_getParentAccountInfo_success(self): | ||
27 | headers = {'Accept': '*/*'} | ||
28 | getData = {'userId': Data.USER_ID, 'type': 1} | ||
29 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
30 | self.result_1 = r.json() | ||
31 | self.assertEqual(self.result_1['status'], 1, 'get parent info fail') | ||
32 | |||
33 | def test_getChildAccountInfo_success(self): | ||
34 | headers = {'Accept': '*/*'} | ||
35 | getData = {'userId': Data.USER_ID, 'type': 2} | ||
36 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
37 | self.result_2 = r.json() | ||
38 | self.assertEqual(self.result_2['status'], 1, 'get child info fail') | ||
39 | |||
40 | |||
41 | #修改个人信息 | ||
42 | class UpdatePersonalInfo(unittest.TestCase): | ||
43 | def setUp(self): | ||
44 | self.base_url = HOST_BOSS + "/personal/update" | ||
45 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
46 | create_testdata.pre_subAccount(Data.PARENT_ID, self.subAccount, 1) | ||
47 | |||
48 | def tearDown(self): | ||
49 | pass | ||
50 | |||
51 | def test_UpdateParentInfo_success(self): | ||
52 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
53 | postData = { | ||
54 | 'userId':Data.PARENT_ID, | ||
55 | 'type': 1, | ||
56 | 'name':'主账户', | ||
57 | 'birthday':'2003-12-12', | ||
58 | 'gradeId': '9', | ||
59 | 'regionId' : '320100', | ||
60 | 'schoolId': '500018', | ||
61 | 'qq': '1313131313', | ||
62 | 'gender': 'female', | ||
63 | 'regionName': '江苏南京玄武', | ||
64 | 'deviceNumber': Data.DEVICE_NUMBER_NEW, | ||
65 | 'address':'幸福小区308' | ||
66 | } | ||
67 | where_data_1 = {'id':Data.PARENT_ID, 'qq': '1313131313'} | ||
68 | where_data_2 = {'user_id':Data.PARENT_ID, 'school_id': '500018'} | ||
69 | where_data_3 = {'user_id':Data.PARENT_ID, 'address':'幸福小区308'} | ||
70 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
71 | self.result_1 = r.json() | ||
72 | self.assertEqual(self.result_1['status'], 1, 'UpdateParentInfo ERROR') | ||
73 | self.assertTrue(db_test.select_('acornuser.acorn_user', where_data_1), 1) | ||
74 | self.assertTrue(db_test.select_('acornuser.ozing_student', where_data_2), 1) | ||
75 | self.assertTrue(db_test.select_('acornuser.acorn_user_extra', where_data_3), 1) | ||
76 | |||
77 | |||
78 | def test_UpdateChildInfo_success(self): | ||
79 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
80 | postData = { | ||
81 | 'userId': Data.PARENT_ID, | ||
82 | 'type': 2, | ||
83 | 'name': '子账户', | ||
84 | 'birthday': '2010-12-12', | ||
85 | 'gradeId': '6', | ||
86 | 'regionId': '330100', | ||
87 | 'schoolId': '6129', | ||
88 | 'qq': '1515151515', | ||
89 | 'gender': 'female', | ||
90 | 'regionName': '浙江杭州西湖', | ||
91 | 'deviceNumber': Data.DEVICE_NUMBER_NEW, | ||
92 | 'address': '鲜花小区808' | ||
93 | } | ||
94 | where_data_child = {'qq': '1515151515', 'address': '鲜花小区808'} | ||
95 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
96 | self.result_2 = r.json() | ||
97 | self.assertEqual(self.result_2['status'], 1, 'UpdateParentInfo ERROR') | ||
98 | self.assertTrue(db_test.select_('acornuser.child_user', where_data_child)) | ||
99 | |||
100 | |||
101 | # 添加和修改个性签名 | ||
102 | class AddorUpdateSignature(unittest.TestCase): | ||
103 | def setUp(self): | ||
104 | self.base_url = HOST_BOSS + "/signature/addOrUpdateSignature" | ||
105 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
106 | create_testdata.pre_subAccount(Data.PARENT_ID, self.subAccount, 0) | ||
107 | create_testdata.checkSignatureExists(Data.PARENT_ID, 1) | ||
108 | create_testdata.checkSignatureExists(self.subAccount, 2) | ||
109 | |||
110 | def tearDown(self): | ||
111 | pass | ||
112 | |||
113 | def test_AddParentSignature_success(self): | ||
114 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
115 | postData = {'userId':Data.PARENT_ID, | ||
116 | 'signature':'who is the clever Polly 谁是聪明的鹦鹉', | ||
117 | 'type': 1} | ||
118 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
119 | self.result_1 = r.json() | ||
120 | self.assertEqual(self.result_1['status'], 1, 'AddParentSignature ERROR') | ||
121 | where_1 = {'user_id':Data.PARENT_ID, | ||
122 | 'signature':'who is the clever Polly 谁是聪明的鹦鹉'} | ||
123 | self.assertEqual(db_test.select_('acornuser.acorn_user_extra', where_1), 1) | ||
124 | |||
125 | def test_UpdateParentSignature_success(self): | ||
126 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
127 | postData = {'userId':Data.PARENT_ID, | ||
128 | 'signature':'clever Polly 一只吵人的鹦鹉', | ||
129 | 'type': 1} | ||
130 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
131 | self.result_2 = r.json() | ||
132 | self.assertEqual(self.result_2['status'], 1, 'UpdateParentSignature ERROR') | ||
133 | where_2 = {'user_id':Data.PARENT_ID, | ||
134 | 'signature':'clever Polly 一只吵人的鹦鹉'} | ||
135 | self.assertEqual(db_test.select_('acornuser.acorn_user_extra', where_2), 1, 'UpdateParentSignature ERROR') | ||
136 | |||
137 | def test_AddChildSignature_success(self): | ||
138 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
139 | postData = {'userId':self.subAccount, | ||
140 | 'signature':'Polly can you spell its name 波利', | ||
141 | 'type': 2} | ||
142 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
143 | self.result_3 = r.json() | ||
144 | self.assertEqual(self.result_3['status'], 1, 'AddChildSignature ERROR') | ||
145 | where_1 = {'sub_account_id':self.subAccount, | ||
146 | 'signature':'Polly can you spell its name 波利'} | ||
147 | self.assertEqual(db_test.select_('acornuser.subAccount_user_extra', where_1), 1, 'AddChildSignature ERROR') | ||
148 | |||
149 | def test_UpdateChildSignature_success(self): | ||
150 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
151 | postData = {'userId':self.subAccount, | ||
152 | 'signature':'波利 P-O-L-L-Y', | ||
153 | 'type': 2} | ||
154 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
155 | self.result_4 = r.json() | ||
156 | self.assertEqual(self.result_4['status'], 1, 'UPDATEChildSignature ERROR') | ||
157 | where_1 = {'sub_account_id':self.subAccount, | ||
158 | 'signature':'波利 P-O-L-L-Y'} | ||
159 | self.assertEqual(db_test.select_('acornuser.subAccount_user_extra', where_1), 1, 'UPDATEChildSignature ERROR') | ||
160 | |||
161 | |||
162 | # 显示个性签名 | ||
163 | class GetSignature(unittest.TestCase): | ||
164 | def setUp(self): | ||
165 | self.base_url = HOST_BOSS + "/signature/info" | ||
166 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
167 | create_testdata.checkSignatureExists(Data.PARENT_ID, 1) | ||
168 | create_testdata.checkSignatureExists(self.subAccount, 2) | ||
169 | |||
170 | def tearDown(self): | ||
171 | pass | ||
172 | |||
173 | def test_getParentSignature_success(self): | ||
174 | headers = {'Accept': '*/*'} | ||
175 | getData = {'userId': Data.PARENT_ID, 'type': 1} | ||
176 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
177 | self.result_1 = r.json() | ||
178 | self.assertEqual(self.result_1['status'], 1, 'get parent Signature fail') | ||
179 | |||
180 | def test_getChildSignature_success(self): | ||
181 | headers = {'Accept': '*/*'} | ||
182 | getData = {'userId': self.subAccount, 'type': 2} | ||
183 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
184 | self.result_2 = r.json() | ||
185 | self.assertEqual(self.result_2['status'], 1, 'get child Signature fail') | ||
186 | |||
187 | |||
188 | #更新用户头像 -- 默认图片 | ||
189 | class UpdatePortraitDefault(unittest.TestCase): | ||
190 | def setUp(self): | ||
191 | self.base_url = HOST_BOSS + "/profile/picture/default" | ||
192 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
193 | create_testdata.pre_subAccount(Data.PARENT_ID, self.subAccount, 0) | ||
194 | |||
195 | def tearDown(self): | ||
196 | pass | ||
197 | |||
198 | def test_UpdateParentPortraitDefault_success(self): | ||
199 | headers = {'Accept': '*/*', 'Content-Type':'application/x-www-form-urlencoded'} | ||
200 | postData = {'userId': Data.PARENT_ID, 'type': 1, | ||
201 | 'defaultImg':'http://hjxprodbucket.oss.aliyuncs.com/static/upload/boss_api/announcement/2017-08-29/61e8d8cf-651f-49c9-beb2-ff1387af390a.png'} | ||
202 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
203 | self.result_1 = r.json() | ||
204 | self.assertEqual(self.result_1['status'], 1, 'UpdateParentPortrait fail') | ||
205 | where = {'user_id': Data.PARENT_ID, | ||
206 | 'portrait':'static/upload/boss_api/announcement/2017-08-29/61e8d8cf-651f-49c9-beb2-ff1387af390a.png'} | ||
207 | self.assertEqual(db_test.select_('acornuser.ozing_student', where), 1, 'UpdateParentPortraitDefault fail') | ||
208 | |||
209 | def test_UpdateChildPortraitDefault_success(self): | ||
210 | headers = {'Accept': '*/*', 'Content-Type':'application/x-www-form-urlencoded'} | ||
211 | postData = {'userId': self.subAccount, 'type': 2, | ||
212 | 'defaultImg': 'http://hjxprodbucket.oss.aliyuncs.com/static/upload/boss_api/announcement/2017-08-29/61e8d8cf-651f-49c9-beb2-ff1387af390a.png'} | ||
213 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
214 | self.result_2 = r.json() | ||
215 | self.assertEqual(self.result_2['status'], 1, 'UpdateChildPortrait fail') | ||
216 | where = {'subAccountId': self.subAccount, | ||
217 | 'image': 'static/upload/boss_api/announcement/2017-08-29/61e8d8cf-651f-49c9-beb2-ff1387af390a.png'} | ||
218 | self.assertEqual(db_test.select_('acornuser.child_user', where), 1, 'UpdateChildPortraitDefault fail') | ||
219 | |||
220 | |||
221 | #更新用户头像-- 上传文件 | ||
222 | class UpdatePortrait(unittest.TestCase): | ||
223 | def setUp(self): | ||
224 | self.base_url = HOST_BOSS + "/profile/picture/update" | ||
225 | img_file_1 = current_dir + '/1.jpg' | ||
226 | img_file_2 = current_dir + '/1.png' | ||
227 | self.img_1 = open(img_file_1, 'rb') | ||
228 | self.img_2 = open(img_file_2, 'rb') | ||
229 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
230 | create_testdata.pre_subAccount(Data.PARENT_ID, self.subAccount, 0) | ||
231 | |||
232 | def tearDown(self): | ||
233 | pass | ||
234 | |||
235 | def test_UpdateParentPortraitDefault_success(self): | ||
236 | headers = {'Accept': '*/*', 'Content-Type':'multipart/form-data; boundary=cada83b1d4b82a7ccd28ae8f7f6d6'} | ||
237 | postData = {'userId': Data.PARENT_ID, 'type': 1} | ||
238 | file = {'img': self.img_1} | ||
239 | r = requests.post(self.base_url, data=postData, files=file) | ||
240 | ss = r.request | ||
241 | self.img_1.close() | ||
242 | self.result_1 = r.json() | ||
243 | self.assertEqual(self.result_1['status'], 1, 'UpdateParentPortrait fail') | ||
244 | self.assertEqual(len(self.result_1['data']), 1, 'UpdateParentPortrait data fail') | ||
245 | |||
246 | def test_UpdateChildPortrait_success(self): | ||
247 | headers = {'Accept': '*/*', 'Content-Type':'multipart/form-data; boundary=fa0cada83b1d4b82a7ccd28ae8f7f6d6'} | ||
248 | postData = {'userId': self.subAccount, 'type': 2} | ||
249 | file = {'img': self.img_2} | ||
250 | r = requests.post(self.base_url, data=postData, files=file) | ||
251 | ss = r.request | ||
252 | self.img_2.close() | ||
253 | self.result_2 = r.json() | ||
254 | self.assertEqual(self.result_2['status'], 1, 'UpdateChildPortrait fail') | ||
255 | self.assertEqual(len(self.result_2['data']), 1, 'UpdateChildPortrait data fail') | ||
256 | |||
257 | |||
258 |
test_cases/press.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | from data_fixture.mysql_db import DB | ||
10 | |||
11 | db_test = DB() | ||
12 | |||
13 | |||
14 | # 获取教材版本列表 | ||
15 | class GetPressList(unittest.TestCase): | ||
16 | def setUp(self): | ||
17 | self.base_url = HOST_BOSS + '/press/list' | ||
18 | |||
19 | def tearDown(self): | ||
20 | print(self.result) | ||
21 | |||
22 | def test_getPressList_success(self): | ||
23 | headers = {'Accept': '*/*'} | ||
24 | getData = {'subjectName': '数学'} | ||
25 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
26 | self.result = r.json() | ||
27 | self.assertEqual(self.result['status'], 1, 'getPressList Error') | ||
28 | self.assertTrue(len(self.result['data']) > 1, 'getPressList data Error') | ||
29 | |||
30 | |||
31 | # 获取用户版本信息接口 | ||
32 | class GetUserPressInfo(unittest.TestCase): | ||
33 | def setUp(self): | ||
34 | self.base_url = HOST_BOSS + '/userPress/info' | ||
35 | CreateTestData.pre_GetUserPressInfo(Data.USER_ID) | ||
36 | |||
37 | def tearDown(self): | ||
38 | print(self.result) | ||
39 | |||
40 | def test_getPressList_success(self): | ||
41 | headers = {'Accept': '*/*'} | ||
42 | getData = {'userId': Data.USER_ID, 'gradeId': 9} | ||
43 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
44 | self.result = r.json() | ||
45 | self.assertEqual(self.result['status'], 1, 'GetUserPressInfo Error') | ||
46 | data = self.result['data'] | ||
47 | for item in data: | ||
48 | if item['subject'] == '语文': | ||
49 | press_to_check = item['press'] | ||
50 | self.assertEqual(press_to_check, '北京师范大学出版社', 'GetUserPressInfo data Error') | ||
51 | |||
52 | |||
53 | # 修改版本信息接口 | ||
54 | class UpdateUserPressInfo(unittest.TestCase): | ||
55 | def setUp(self): | ||
56 | self.base_url = HOST_BOSS + '/userPress/update' | ||
57 | |||
58 | def tearDown(self): | ||
59 | print(self.result) | ||
60 | |||
61 | def test_getPressList_success(self): | ||
62 | headers = {'Accept': '*/*', 'Content-Type': 'application/x-www-form-urlencoded'} | ||
63 | postData = {'userId': Data.USER_ID, | ||
64 | 'chemistry': '山东教育出版社', | ||
65 | 'chinese': '江苏教育出版社', | ||
66 | 'biology': '人民教育出版社', | ||
67 | 'geography': '人民教育出版社', | ||
68 | 'physics': '人民教育出版社', | ||
69 | 'english': '外语教学与研究出版社', | ||
70 | 'political': '人民教育出版社', | ||
71 | 'math': '江苏科学技术出版社', | ||
72 | 'history': '人民教育出版社' | ||
73 | } | ||
74 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
75 | self.result = r.json() | ||
76 | self.assertEqual(self.result['status'], 1, 'UpdateUserPressInfo Error') | ||
77 | where = {'user_id': Data.USER_ID, | ||
78 | 'chemistry': '山东教育出版社', | ||
79 | 'chinese': '江苏教育出版社', | ||
80 | 'biology': '人民教育出版社', | ||
81 | 'geography': '人民教育出版社', | ||
82 | 'physics': '人民教育出版社', | ||
83 | 'english': '外语教学与研究出版社', | ||
84 | 'political': '人民教育出版社', | ||
85 | 'math': '江苏科学技术出版社', | ||
86 | 'history': '人民教育出版社' | ||
87 | } | ||
88 | self.assertEqual(db_test.select_('acornuser.user_press', where), 1, 'UpdateUserPressInfo data Error') | ||
89 | |||
90 | |||
91 | |||
92 |
test_cases/region_grade_school.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS | ||
7 | |||
8 | # 省 | ||
9 | class GetProvince(unittest.TestCase): | ||
10 | def setUp(self): | ||
11 | self.base_url = HOST_BOSS + "/ozing/provinces" | ||
12 | |||
13 | def tearDown(self): | ||
14 | print(self.result) | ||
15 | |||
16 | def test_getProvince_success(self): | ||
17 | headers = {'Accept': '*/*'} | ||
18 | r = requests.get(self.base_url, headers=headers) | ||
19 | self.result = r.json() | ||
20 | self.assertEqual(self.result['status'], 100, 'get province fail') | ||
21 | self.assertTrue(len(self.result['provinces']) > 0, 'province data wrong') | ||
22 | |||
23 | # 市 | ||
24 | class GetCities(unittest.TestCase): | ||
25 | def setUp(self): | ||
26 | self.base_url = HOST_BOSS + "/ozing/cities" | ||
27 | self.regionId = '330000' #浙江 | ||
28 | self.city ='330100' # 杭州 | ||
29 | |||
30 | def tearDown(self): | ||
31 | print(self.result) | ||
32 | |||
33 | def test_getCities_success(self): | ||
34 | headers = {'Accept': '*/*'} | ||
35 | getData = {'regionId': self.regionId} | ||
36 | r = requests.get(self.base_url, params=getData) | ||
37 | self.result = r.json() | ||
38 | self.assertEqual(self.result['status'], 100, 'get cities fail') | ||
39 | self.assertTrue(len(self.result['cities']) > 0, 'cities data wrong') | ||
40 | |||
41 | # 区 | ||
42 | class GetCounties(unittest.TestCase): | ||
43 | def setUp(self): | ||
44 | self.base_url = HOST_BOSS + "/ozing/counties" | ||
45 | self.regionId = '330100' # 杭州 | ||
46 | self.county ='330106' # 西湖 | ||
47 | |||
48 | def tearDown(self): | ||
49 | print(self.result) | ||
50 | |||
51 | def test_getCounties_success(self): | ||
52 | headers = {'Accept': '*/*'} | ||
53 | getData = {'regionId': self.regionId} | ||
54 | r = requests.get(self.base_url, params=getData) | ||
55 | self.result = r.json() | ||
56 | self.assertEqual(self.result['status'], 100, 'get counties fail') | ||
57 | self.assertTrue(len(self.result['counties']) > 0, 'counties data wrong') | ||
58 | |||
59 | # 年级 | ||
60 | class GetGrades(unittest.TestCase): | ||
61 | def setUp(self): | ||
62 | self.base_url = HOST_BOSS + "/grades" | ||
63 | |||
64 | def tearDown(self): | ||
65 | print(self.result) | ||
66 | |||
67 | def test_getGrades_success(self): | ||
68 | headers = {'Accept': 'application/json'} | ||
69 | r = requests.get(self.base_url, headers=headers) | ||
70 | self.result = r.json() | ||
71 | self.assertTrue(len(self.result['data']) > 0, 'grades data wrong') | ||
72 | |||
73 | |||
74 | # 学校 | ||
75 | class GetSchools(unittest.TestCase): | ||
76 | def setUp(self): | ||
77 | self.base_url = HOST_BOSS + "/school/get" | ||
78 | self.regionId = '330106' #西湖 | ||
79 | self.gradeId = '6' #五年级 | ||
80 | |||
81 | def tearDown(self): | ||
82 | print(self.result) | ||
83 | |||
84 | def test_getSchools_success(self): | ||
85 | headers = {'Accept': 'application/json'} | ||
86 | getData = {'regionId': self.regionId, 'gradeId': self.gradeId} | ||
87 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
88 | self.result = r.json() | ||
89 | self.assertTrue(len(self.result['data']) > 0, 'school data wrong') | ||
90 |
test_cases/register.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | from data_fixture.mysql_db import DB | ||
10 | import os | ||
11 | from requests_toolbelt import MultipartEncoder | ||
12 | |||
13 | db_test = DB() | ||
14 | current_dir = str(os.path.dirname(__file__)) | ||
15 | |||
16 | #手机号重复验证 | ||
17 | class PhoneUsedCheck(unittest.TestCase): | ||
18 | def setUp(self): | ||
19 | self.base_url = HOST_BOSS + "/ozing/timer/user/registered" | ||
20 | CreateTestData.pre_phoneUsedCheck(Data.USER_PHONE_USED, True) | ||
21 | CreateTestData.pre_phoneUsedCheck(Data.USER_PHONE_UNUSED, False) | ||
22 | |||
23 | def tearDown(self): | ||
24 | print(self.result) | ||
25 | |||
26 | # 注册过的手机号 | ||
27 | def test_phone_used(self): | ||
28 | getData = {'mobile':Data.USER_PHONE_USED} | ||
29 | r = requests.get(self.base_url, params=getData) | ||
30 | self.result = r.json() | ||
31 | self.assertEqual(self.result['status'], True) | ||
32 | |||
33 | # 手机号未注册 | ||
34 | def test_phone_unused(self): | ||
35 | getData = {'mobile':Data.USER_PHONE_UNUSED} | ||
36 | r = requests.get(self.base_url, params=getData) | ||
37 | self.result = r.json() | ||
38 | self.assertEqual(self.result['status'], False) | ||
39 | |||
40 | |||
41 | # 获取验证码 --register | ||
42 | class GetAuthCode(unittest.TestCase): | ||
43 | def setUp(self): | ||
44 | self.base_url = HOST_BOSS + "/ozing/timer/user/fetchAuthCode" | ||
45 | self.mobile = '13833333333' | ||
46 | |||
47 | def tearDown(self): | ||
48 | print(self.result) | ||
49 | |||
50 | def test_getAuthCode_success(self): | ||
51 | headers = {'Accept': '*/*'} | ||
52 | postData = {'mobile': self.mobile, 'type': 'register'} | ||
53 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
54 | self.result = r.json() | ||
55 | self.assertEqual(self.result['status'], 100) | ||
56 | |||
57 | |||
58 | #用户注册 | ||
59 | class SignIn(unittest.TestCase): | ||
60 | def setUp(self): | ||
61 | self.base_url = HOST_BOSS + "/ozing/timer/anking/user" | ||
62 | self.smsCode = CreateTestData.fet_authCode(Data.USER_PHONE) | ||
63 | CreateTestData.pre_phoneUsedCheck(Data.USER_PHONE, False) | ||
64 | |||
65 | def tearDown(self): | ||
66 | print(self.result) | ||
67 | |||
68 | def test_signIn_success(self): | ||
69 | headers = {'Content-Type': 'application/json', 'Accept': '*/*'} | ||
70 | postData = { | ||
71 | "username": Data.USER_PHONE, | ||
72 | "password": 'Hjx111111', | ||
73 | "source": 'Android', | ||
74 | "smscode": self.smsCode | ||
75 | } | ||
76 | r = requests.post(self.base_url, headers=headers, json=postData) | ||
77 | self.result = r.json() | ||
78 | self.assertEqual(self.result['status'], 100) | ||
79 | |||
80 | |||
81 | # 检查用户注册信息是否完整 | ||
82 | class RegisterExtrainfoCheck(unittest.TestCase): | ||
83 | def setUp(self): | ||
84 | self.base_url = HOST_BOSS + '/register/extrainfo/check' | ||
85 | CreateTestData.pre_register_extrainfo_check(Data.USER_ID, True) | ||
86 | CreateTestData.pre_register_extrainfo_check(Data.USER_ID_INCOMPLETE, False) | ||
87 | |||
88 | def tearDown(self): | ||
89 | pass | ||
90 | |||
91 | def test_checkRegisterExtrainfo_Complete_success(self): | ||
92 | headers = {'Accept': '*/*'} | ||
93 | getData = {'userId': Data.USER_ID} | ||
94 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
95 | self.result_1 = r.json() | ||
96 | self.assertEqual(self.result_1['status'], 1, 'test_checkRegisterExtrainfo_Complete fail') | ||
97 | self.assertEqual(self.result_1['data']['isRegisterInfoComplete'], True, 'test_checkRegisterExtrainfo_Complete data fail') | ||
98 | |||
99 | def test_checkRegisterExtrainfo_inComplete_success(self): | ||
100 | headers = {'Accept': '*/*'} | ||
101 | getData = {'userId': Data.USER_ID_INCOMPLETE} | ||
102 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
103 | self.result_2 = r.json() | ||
104 | self.assertEqual(self.result_2['status'], 1, 'test_checkRegisterExtrainfo_inComplete fail') | ||
105 | self.assertEqual(self.result_2['data']['isRegisterInfoComplete'], False, | ||
106 | 'test_checkRegisterExtrainfo_inComplete data fail') | ||
107 | |||
108 | |||
109 | # 提交注册信息 | ||
110 | class RegisterExtrainfoSubmit(unittest.TestCase): | ||
111 | def setUp(self): | ||
112 | self.base_url = HOST_BOSS + '/register/extrainfo/submit' | ||
113 | |||
114 | def tearDown(self): | ||
115 | print(self.result) | ||
116 | |||
117 | def test_RegisterExtrainfoSubmit_success(self): | ||
118 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
119 | postData = { | ||
120 | 'name': '测试测试lalalallal', | ||
121 | 'gradeId': 7, | ||
122 | 'schoolId': 68779, | ||
123 | 'regionName': '浙江杭州西湖', | ||
124 | 'regionId': 330106, | ||
125 | 'userId': Data.USER_ID, | ||
126 | 'chinese': '北京出版社', | ||
127 | 'english': '人民教育出版社', | ||
128 | 'math': '人民教育出版社' | ||
129 | } | ||
130 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
131 | self.result = r.json() | ||
132 | self.assertEqual(self.result['status'], 1, 'RegisterExtrainfoSubmit Error') | ||
133 | where_1 = {'id': Data.USER_ID,'nickname': '测试测试lalalallal'} | ||
134 | where_2 = {'user_id': Data.USER_ID, | ||
135 | 'grade_id': 7, | ||
136 | 'school_id': 68779, | ||
137 | 'region_name': '浙江杭州西湖', | ||
138 | 'region_id': 330106} | ||
139 | where_3 = {'user_id': Data.USER_ID, | ||
140 | 'chinese': '北京出版社', | ||
141 | 'english': '人民教育出版社', | ||
142 | 'math': '人民教育出版社' | ||
143 | } | ||
144 | self.assertEqual(db_test.select_('acornuser.acorn_user', where_1), 1, 'RegisterExtrainfoSubmit Error') | ||
145 | self.assertEqual(db_test.select_('acornuser.ozing_student', where_2), 1, 'RegisterExtrainfoSubmit Error') | ||
146 | self.assertEqual(db_test.select_('acornuser.user_press', where_3), 1, 'RegisterExtrainfoSubmit Error') | ||
147 | |||
148 | |||
149 | #账户管理界面更换手机号绑定 | ||
150 | class UpdateUserNameByUserId(unittest.TestCase): | ||
151 | def setUp(self): | ||
152 | self.base_url = HOST_BOSS + '/electronicCard/updateUserNameByUserId' | ||
153 | self.authCode_1 = CreateTestData.fet_authCode(Data.USER_PHONE_CHANGE_EXISTS) | ||
154 | self.authCode_2 = CreateTestData.fet_authCode(Data.USER_PHONE_CHANGE) | ||
155 | CreateTestData.pre_phoneUsedCheck(Data.USER_PHONE_CHANGE_EXISTS, True) | ||
156 | CreateTestData.pre_phoneUsedCheck(Data.USER_PHONE_CHANGE, False) | ||
157 | |||
158 | def tearDown(self): | ||
159 | print(self.result) | ||
160 | |||
161 | def test_UpdateUserNameByUserId_phoneExists_success(self): | ||
162 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
163 | postData = { | ||
164 | 'username': Data.USER_PHONE_CHANGE_EXISTS, | ||
165 | 'authCode': self.authCode_1, | ||
166 | 'userId': Data.USER_ID | ||
167 | } | ||
168 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
169 | self.result = r.json() | ||
170 | self.assertEqual(self.result['status'], 1006, 'UpdateUserNameByUserId_phoneExists Error') | ||
171 | |||
172 | def test_UpdateUserNameByUserId_success(self): | ||
173 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
174 | postData = { | ||
175 | 'username': Data.USER_PHONE_CHANGE, | ||
176 | 'authCode': self.authCode_2, | ||
177 | 'userId': Data.USER_ID | ||
178 | } | ||
179 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
180 | self.result = r.json() | ||
181 | self.assertEqual(self.result['status'], 1, 'UpdateUserNameByUserId Error') | ||
182 | |||
183 | |||
184 | # 添加用户反馈 | ||
185 | class AddFeedBack(unittest.TestCase): | ||
186 | def setUp(self): | ||
187 | self.base_url = HOST_BOSS + '/feedback/add' | ||
188 | img_file = current_dir + '/1.png' | ||
189 | self.img = open(img_file, 'rb') | ||
190 | |||
191 | def tearDown(self): | ||
192 | print(self.result) | ||
193 | |||
194 | def test_AddFeedBack_success(self): | ||
195 | headers = {'Content-Type': 'multipart/form-data; boundary=fa0cada83b1d4b82a7ccd28ae8f7f6d6', 'Accept': '*/*'} | ||
196 | postData = { | ||
197 | 'userId': Data.USER_ID, | ||
198 | 'content': '11111feedback哦哦哦', | ||
199 | 'contact': '00000000', | ||
200 | 'feedtype': '个人中心' | ||
201 | } | ||
202 | file = {'imgs': self.img} | ||
203 | |||
204 | r = requests.post(self.base_url, data=postData, files=file) | ||
205 | #r = requests.post(self.base_url, headers=headers, data=postData) | ||
206 | ss = r.request | ||
207 | self.img.close() | ||
208 | self.result = r.json() | ||
209 | self.assertEqual(self.result['status'], 1, 'AddFeedBack Error') | ||
210 | select = {'userId': Data.USER_ID, | ||
211 | 'content': '11111feedback哦哦哦', | ||
212 | 'contact': '00000000', | ||
213 | 'feedtype': '个人中心'} | ||
214 | self.assertTrue(db_test.select_('acornuser.feedback', select) > 0, 'AddFeedBack data insert Error') | ||
215 | |||
216 | |||
217 | # 获取最近观看视频列表 | ||
218 | class GetRecentVideo(unittest.TestCase): | ||
219 | def setUp(self): | ||
220 | self.base_url = HOST_BOSS + '/personal/video/recent' | ||
221 | CreateTestData.pre_getRecentVideo(Data.USER_ID_NO_VIDEO, 0) | ||
222 | CreateTestData.pre_getRecentVideo(Data.USER_ID_VIDEO, 1) | ||
223 | |||
224 | def tearDown(self): | ||
225 | pass | ||
226 | |||
227 | def test_GetRecentVideo_noVideo_success(self): | ||
228 | getData = {'userId': Data.USER_ID_NO_VIDEO, | ||
229 | 'pageNum': 1} | ||
230 | r = requests.get(self.base_url, params=getData) | ||
231 | self.result_1 = r.json() | ||
232 | self.assertEqual(self.result_1['status'], 1000, 'GetRecentVideo-noVideo fail') | ||
233 | |||
234 | def test_GetRecentVideo_success(self): | ||
235 | getData = {'userId': Data.USER_ID_VIDEO, | ||
236 | 'pageNum': 1} | ||
237 | r = requests.get(self.base_url, params=getData) | ||
238 | self.result_2 = r.json() | ||
239 | self.assertEqual(self.result_2['status'], 1, 'GetRecentVideo fail') | ||
240 | |||
241 | |||
242 | |||
243 | |||
244 |
test_cases/sub_account.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | from data_fixture.mysql_db import DB | ||
10 | import uuid | ||
11 | |||
12 | db_test = DB() | ||
13 | |||
14 | #添加子账户 | ||
15 | class AddSubAccount(unittest.TestCase): | ||
16 | def setUp(self): | ||
17 | self.base_url = HOST_BOSS + '/childUser/addChildUser' | ||
18 | CreateTestData.pre_AddSubAccount(Data.PARENT_ID) | ||
19 | |||
20 | def tearDown(self): | ||
21 | print(self.result) | ||
22 | |||
23 | def test_addSubAccount_success(self): | ||
24 | headers = {'Content-Type': 'application/x-www-form-urlencoded', 'Accept': '*/*'} | ||
25 | postData = {'parentId': Data.PARENT_ID, | ||
26 | 'image': Data.SUB_ACC_IMAGE, | ||
27 | 'name': '测试sub', | ||
28 | 'gradeId': '6', | ||
29 | 'schoolId': Data.SUB_ACC_SCHOOL_ID_1, | ||
30 | 'regionId': Data.SUB_ACC_REGION_ID_1, | ||
31 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
32 | 'regionName': Data.SUB_ACC_REGION_NAME_1 | ||
33 | } | ||
34 | r = requests.post(self.base_url, headers=headers, data=postData) | ||
35 | self.result = r.json() | ||
36 | self.assertEqual(db_test.select_('acornuser.child_user', {'parent_id': Data.PARENT_ID}), 1, 'addSubAccount Error') | ||
37 | self.assertEqual(self.result['status'], 1, 'addSubAccount Error') | ||
38 | |||
39 | |||
40 | #查找子账户信息 | ||
41 | class GetSubAccount(unittest.TestCase): | ||
42 | def setUp(self): | ||
43 | self.base_url = HOST_BOSS + '/childUser/info' | ||
44 | self.subAccount_1 = str(uuid.uuid4()).replace('-', '') | ||
45 | self.subAccount_2 = str(uuid.uuid4()).replace('-', '') | ||
46 | CreateTestData.pre_subAccount(Data.PARENT_ID, self.subAccount_1, 0) | ||
47 | CreateTestData.pre_subAccount(Data.PARENT_ID, self.subAccount_2, 1) | ||
48 | |||
49 | def tearDown(self): | ||
50 | print(self.result) | ||
51 | |||
52 | def test_getSubAccount_success(self): | ||
53 | headers = {'Accept': '*/*'} | ||
54 | getData = {'userId': Data.PARENT_ID, 'deviceNumber':Data.DEVICE_NUMBER_CUS_BIND} | ||
55 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
56 | self.result = r.json() | ||
57 | self.assertEqual(self.result['status'], 1, 'getSubAccount Error') | ||
58 | self.assertTrue(len(self.result['data']) > 1, 'getSubAccount data Error') | ||
59 | |||
60 | |||
61 | #删除子账户 | ||
62 | class DelSubAccount(unittest.TestCase): | ||
63 | def setUp(self): | ||
64 | self.base_url = HOST_BOSS + '/childUser/delete' | ||
65 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
66 | CreateTestData.pre_subAccount(Data.PARENT_ID, self.subAccount, 0) | ||
67 | |||
68 | def tearDown(self): | ||
69 | print(self.result) | ||
70 | |||
71 | def test_delSubAccount_success(self): | ||
72 | headers = {'Accept': '*/*'} | ||
73 | getData = {'subAccountId': self.subAccount} | ||
74 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
75 | self.result = r.json() | ||
76 | self.assertEqual(db_test.select_('acornuser.child_user', {'subAccountId': self.subAccount}), 0, 'delSubAccount Error') | ||
77 | self.assertEqual(self.result['status'], 1, 'delSubAccount ERROR') | ||
78 | |||
79 | |||
80 | #切换账户 | ||
81 | class SwitchAccounts(unittest.TestCase): | ||
82 | def setUp(self): | ||
83 | self.base_url = HOST_BOSS + '/childUser/update' | ||
84 | self.subAccount = str(uuid.uuid4()).replace('-', '') | ||
85 | CreateTestData.pre_subAccount(Data.PARENT_ID, self.subAccount, 0) | ||
86 | |||
87 | def tearDown(self): | ||
88 | print(self.result) | ||
89 | |||
90 | def test_swichToSubAccount_success(self): | ||
91 | headers = {'Accept': '*/*'} | ||
92 | getData = {'subAccountId': self.subAccount, | ||
93 | 'userId': Data.PARENT_ID, | ||
94 | 'deviceNumber' : Data.DEVICE_NUMBER_CUS_BIND, | ||
95 | 'type': 2} | ||
96 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
97 | self.result = r.json() | ||
98 | where_data = {'parent_id': Data.PARENT_ID,'subAccountId': self.subAccount, 'status':1} | ||
99 | self.assertEqual(db_test.select_('acornuser.child_user', where_data), 1, 'swichToSubAccount Error') | ||
100 | self.assertEqual(self.result['status'], 1, 'swichToSubAccount ERROR') | ||
101 | |||
102 | def test_swichToParentAccount_success(self): | ||
103 | headers = {'Accept': '*/*'} | ||
104 | getData = {'userId': Data.PARENT_ID, | ||
105 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
106 | 'type': 1} | ||
107 | r = requests.get(self.base_url, headers=headers, params=getData) | ||
108 | self.result = r.json() | ||
109 | where_data = {'userId': Data.PARENT_ID, | ||
110 | 'deviceNumber': Data.DEVICE_NUMBER_CUS_BIND, | ||
111 | 'status': 1} | ||
112 | self.assertEqual(db_test.select_('acornuser.acorn_user_status', where_data), 1, 'swichToParentAccount Error') | ||
113 | self.assertEqual(self.result['status'], 1, 'swichToParentAccount ERROR') | ||
114 | |||
115 | |||
116 | |||
117 | |||
118 | |||
119 |
test_cases/subject_sync.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | import requests | ||
6 | from data_fixture.config_data import HOST_BOSS, HOST_STA, HOST_RES | ||
7 | from data_fixture import create_testdata as CreateTestData | ||
8 | from data_fixture import config_data as Data | ||
9 | from data_fixture.mysql_db import DB | ||
10 | import time | ||
11 | from datetime import date | ||
12 | |||
13 | db_test = DB() | ||
14 | |||
15 | #获取同步视频接口 | ||
16 | class ClassNameVideo(unittest.TestCase): | ||
17 | def setUp(self): | ||
18 | self.base_url = HOST_RES + '/className/video' | ||
19 | |||
20 | def tearDown(self): | ||
21 | pass | ||
22 | |||
23 | def test_ClassNameVideo_success(self): | ||
24 | getData = {'textName': '秋天的怀念', | ||
25 | 'press': '人民教育出版社', | ||
26 | 'subject': '语文', | ||
27 | 'gradeName': '7年级'} | ||
28 | r = requests.get(self.base_url, params=getData) | ||
29 | self.result_1 = r.json() | ||
30 | self.assertEqual(self.result_1['status'], 1, 'test_ClassNameVideo_success Error') | ||
31 | |||
32 | def test_ClassNameVideo_noData(self): | ||
33 | getData = {'textName': '秋天 的怀念', | ||
34 | 'press': '人民教育出版社', | ||
35 | 'subject': '语文', | ||
36 | 'gradeName': '7年级'} | ||
37 | r = requests.get(self.base_url, params=getData) | ||
38 | self.result_2 = r.json() | ||
39 | self.assertEqual(self.result_2['status'], 1000, 'test_ClassNameVideo_noData Error') | ||
40 | |||
41 | |||
42 | #获取知识点视频 | ||
43 | class PointVideo(unittest.TestCase): | ||
44 | def setUp(self): | ||
45 | self.base_url = HOST_RES + '/point/video' | ||
46 | |||
47 | def tearDown(self): | ||
48 | pass | ||
49 | |||
50 | def test_PointVideo_success(self): | ||
51 | getData = {'textName': '秋天的怀念', | ||
52 | 'press': '人民教育出版社', | ||
53 | 'subject': '语文', | ||
54 | 'gradeName': '7年级', | ||
55 | 'point':'说明文阅读5说明文的结构||议论文的定义和分类'} | ||
56 | r = requests.get(self.base_url, params=getData) | ||
57 | self.result_1 = r.json() | ||
58 | self.assertEqual(self.result_1['status'], 1, 'test_PointVideo_success Error') | ||
59 | |||
60 | def test_PointVideo_noData(self): | ||
61 | getData = {'textName': '秋天的怀念', | ||
62 | 'press': '人民教育出版社', | ||
63 | 'subject': '语文', | ||
64 | 'gradeName': '7年级', | ||
65 | 'point': '说明文阅读5说明文的结构'} | ||
66 | r = requests.get(self.base_url, params=getData) | ||
67 | self.result_2 = r.json() | ||
68 | self.assertEqual(self.result_2['status'], 1000, 'test_PointVideo_noData Error') | ||
69 | |||
70 | |||
71 | #课程中心PK练习抽题接口 | ||
72 | class SubjectTest(unittest.TestCase): | ||
73 | def setUp(self): | ||
74 | self.base_url = HOST_BOSS + '/subject/test/' | ||
75 | |||
76 | def tearDown(self): | ||
77 | pass | ||
78 | |||
79 | def test_SubjectTest_success(self): | ||
80 | getData = {'subjectName': '数学', | ||
81 | 'questionPoint': '二元一次方程||二元一次方程组的解', | ||
82 | 'gradeId': '10', | ||
83 | 'textName': '二元一次方程组'} | ||
84 | url = self.base_url + 'math' | ||
85 | r = requests.get(url, params=getData) | ||
86 | self.result_1 = r.json() | ||
87 | self.assertEqual(self.result_1['status'], 1, 'test_SubjectTest_success Error') | ||
88 | |||
89 | |||
90 | #巩固练习抽题接口 | ||
91 | class ConsolidationExercise(unittest.TestCase): | ||
92 | def setUp(self): | ||
93 | self.base_url = HOST_BOSS + '/consolidation/exercise' | ||
94 | |||
95 | def tearDown(self): | ||
96 | pass | ||
97 | |||
98 | def test_ConsolidationExercise_success(self): | ||
99 | getData = {'subjectName': '数学', | ||
100 | 'gradeId': '10', | ||
101 | 'secondPoint': '二元一次方程||二元一次方程组的解', | ||
102 | 'textName': '二元一次方程组', | ||
103 | 'difficultyLevel': '基础卷'} | ||
104 | r = requests.get(self.base_url, params=getData) | ||
105 | self.result = r.json() | ||
106 | self.assertEqual(self.result['status'], 1, 'test_ConsolidationExercise_success Error') | ||
107 | self.assertTrue(len(self.result['data']) > 1) | ||
108 | |||
109 | |||
110 | |||
111 | |||
112 |
test_suites/__pycache__/test_elecCard.cpython-36.pyc
No preview for this file type
test_suites/test_elecCard.py
File was created | 1 | #!/usr/bin/env python | |
2 | # -*- coding: utf-8 -*- | ||
3 | |||
4 | import unittest | ||
5 | |||
6 | from test_cases import eleccard_setUp | ||
7 | |||
8 | from test_cases import eleccard_check | ||
9 | |||
10 | # 添加保卡 | ||
11 | def suites_addElecCard(): | ||
12 | suite = unittest.TestSuite() | ||
13 | suite.addTest(eleccard_check.CheckElecCardBind('test_checkElecCard_unbind')) | ||
14 | suite.addTest(eleccard_setUp.SetUpElecCard('test_addElecCard_success')) | ||
15 | suite.addTest(eleccard_check.CheckElecCardBind('test_checkElecCard_customerMachine')) | ||
16 | suite.addTest(eleccard_check.GetCardInfo('test_getCardInfo_success')) | ||
17 | return suite | ||
18 | |||
19 | # 客机置为样机 | ||
20 | def suites_setElecCardtoSample(): | ||
21 | suite = unittest.TestSuite() | ||
22 | # 机器是客机状态 | ||
23 | suite.addTest(eleccard_check.CheckElecCardBind('test_checkElecCard_customerMachine')) | ||
24 | # 置为样机 | ||
25 | suite.addTest(eleccard_setUp.SetToSample('test_updateToSample_success')) | ||
26 | # 检验判断为客机 | ||
27 | suite.addTest(eleccard_check.CheckElecCardBind('test_checkElecCard_sampleMachine')) | ||
28 | return suite | ||
29 | |||
30 | # 样机置为客机 | ||
31 | def suites_setElecCardtoCustomer(): | ||
32 | suite = unittest.TestSuite() | ||
33 | # 机器是样机状态 | ||
34 | suite.addTest(eleccard_check.CheckElecCardBind('test_checkElecCard_sampleMachine')) | ||
35 | # 置为客机 | ||
36 | suite.addTest(eleccard_setUp.SetToCustomerMachine('test_updateToCustomer_success')) | ||
37 | # 检查需要添加保卡 | ||
38 | suite.addTest(eleccard_check.CheckElecCardBind('test_checkElecCard_unbind')) | ||
39 | |||
40 | # 客机修改保卡 | ||
41 | |||
42 | |||
43 | # 客机解绑保卡 |