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
... | ... | @@ -0,0 +1,11 @@ |
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> | |
0 | 12 | \ No newline at end of file | ... | ... |
.idea/inspectionProfiles/Project_Default.xml
... | ... | @@ -0,0 +1,12 @@ |
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> | |
0 | 13 | \ No newline at end of file | ... | ... |
.idea/misc.xml
... | ... | @@ -0,0 +1,4 @@ |
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> | |
0 | 5 | \ No newline at end of file | ... | ... |
.idea/modules.xml
... | ... | @@ -0,0 +1,8 @@ |
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> | |
0 | 9 | \ No newline at end of file | ... | ... |
.idea/vcs.xml
.idea/workspace.xml
... | ... | @@ -0,0 +1,920 @@ |
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> | |
0 | 921 | \ No newline at end of file | ... | ... |
HTMLTestRunner.py
... | ... | @@ -0,0 +1,857 @@ |
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) | ... | ... |
HTMLTestRunner.pyc
No preview for this file type
HTMLTestRunner_bak.py
... | ... | @@ -0,0 +1,857 @@ |
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) | ... | ... |
README
... | ... | @@ -0,0 +1 @@ |
1 | +API test scripts about APIs in Pad3.o | ... | ... |
__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
... | ... | @@ -0,0 +1,23 @@ |
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/' | |
0 | 24 | \ No newline at end of file | ... | ... |
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
... | ... | @@ -0,0 +1,85 @@ |
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 | + | ... | ... |
data_fixture/create_testdata.py
... | ... | @@ -0,0 +1,484 @@ |
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 | + | ... | ... |
data_fixture/mysql_db.py
... | ... | @@ -0,0 +1,87 @@ |
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 | + | ... | ... |
data_fixture/test_verify.py
... | ... | @@ -0,0 +1,11 @@ |
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 | + | ... | ... |
report/test_report.html
... | ... | @@ -0,0 +1,303 @@ |
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> | ... | ... |
run_test.py
... | ... | @@ -0,0 +1,31 @@ |
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 | + | ... | ... |
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
... | ... | @@ -0,0 +1,259 @@ |
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 | + | ... | ... |
test_cases/debugggggg.py
... | ... | @@ -0,0 +1,118 @@ |
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 | + | ... | ... |
test_cases/eleccard_check.py
... | ... | @@ -0,0 +1,60 @@ |
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') | ... | ... |
test_cases/eleccard_setUp.py
... | ... | @@ -0,0 +1,128 @@ |
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 | + | ... | ... |
test_cases/parent_space.py
... | ... | @@ -0,0 +1,106 @@ |
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 | + | ... | ... |
test_cases/personal_info.py
... | ... | @@ -0,0 +1,257 @@ |
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 | + | ... | ... |
test_cases/press.py
... | ... | @@ -0,0 +1,91 @@ |
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 | + | ... | ... |
test_cases/region_grade_school.py
... | ... | @@ -0,0 +1,89 @@ |
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') | ... | ... |
test_cases/register.py
... | ... | @@ -0,0 +1,243 @@ |
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 | + | ... | ... |
test_cases/sub_account.py
... | ... | @@ -0,0 +1,118 @@ |
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 | + | ... | ... |
test_cases/subject_sync.py
... | ... | @@ -0,0 +1,111 @@ |
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 | + | ... | ... |
test_suites/__pycache__/test_elecCard.cpython-36.pyc
No preview for this file type
test_suites/test_elecCard.py
... | ... | @@ -0,0 +1,43 @@ |
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 | +# 客机解绑保卡 | |
0 | 44 | \ No newline at end of file | ... | ... |