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 | ... | ... |