diff --git "a/content/post/Development/Git/GitHub \346\235\203\351\231\220\346\240\241\351\252\214\345\244\261\350\264\245\347\273\231\346\210\221\347\232\204\345\220\257\345\217\221.md" "b/content/post/Development/Git/GitHub \346\235\203\351\231\220\346\240\241\351\252\214\345\244\261\350\264\245\347\273\231\346\210\221\347\232\204\345\220\257\345\217\221.md" index 0150b6c..833f1eb 100644 --- "a/content/post/Development/Git/GitHub \346\235\203\351\231\220\346\240\241\351\252\214\345\244\261\350\264\245\347\273\231\346\210\221\347\232\204\345\220\257\345\217\221.md" +++ "b/content/post/Development/Git/GitHub \346\235\203\351\231\220\346\240\241\351\252\214\345\244\261\350\264\245\347\273\231\346\210\221\347\232\204\345\220\257\345\217\221.md" @@ -98,7 +98,7 @@ https://leolee:340d247cxxxxxxxxf39556e38fe2b0baxxxxxxxx@github.com 在Macbook Air中打开`Keychain Access`应用软件,搜索`github`,果然发现存在记录。 -![Mac Keychain of GitHub](/images/Mac_Keychain_GitHub.jpg) +![Mac Keychain of GitHub](/image/Mac_Keychain_GitHub.jpg) 而且,`github.com`这一项还存在两条记录。一条是我的个人账号`debugtalk`,另一条是公司的工作账号`leolee`。 diff --git "a/content/post/Development/Git/\343\200\220GIT\346\212\200\345\267\247\343\200\221\346\270\205\351\231\244\345\216\206\345\217\262\346\217\220\344\272\244\350\256\260\345\275\225\344\270\255\347\232\204\346\225\217\346\204\237\344\277\241\346\201\257.md" "b/content/post/Development/Git/\343\200\220GIT\346\212\200\345\267\247\343\200\221\346\270\205\351\231\244\345\216\206\345\217\262\346\217\220\344\272\244\350\256\260\345\275\225\344\270\255\347\232\204\346\225\217\346\204\237\344\277\241\346\201\257.md" index 0515e26..f8ff6f0 100644 --- "a/content/post/Development/Git/\343\200\220GIT\346\212\200\345\267\247\343\200\221\346\270\205\351\231\244\345\216\206\345\217\262\346\217\220\344\272\244\350\256\260\345\275\225\344\270\255\347\232\204\346\225\217\346\204\237\344\277\241\346\201\257.md" +++ "b/content/post/Development/Git/\343\200\220GIT\346\212\200\345\267\247\343\200\221\346\270\205\351\231\244\345\216\206\345\217\262\346\217\220\344\272\244\350\256\260\345\275\225\344\270\255\347\232\204\346\225\217\346\204\237\344\277\241\346\201\257.md" @@ -9,7 +9,7 @@ tags: - GitHub --- -![](/images/GitHub_hacker.jpg) +![](/image/GitHub_hacker.jpg) ## 背景介绍 diff --git "a/content/post/Development/JavaScript/\346\265\213\350\257\225\347\273\223\346\236\234\346\212\245\350\241\250\345\261\225\347\216\260\357\274\232Web\351\241\265\351\235\242\347\273\230\345\210\266\345\244\232\345\261\202\347\272\247\350\241\250\346\240\274.md" "b/content/post/Development/JavaScript/\346\265\213\350\257\225\347\273\223\346\236\234\346\212\245\350\241\250\345\261\225\347\216\260\357\274\232Web\351\241\265\351\235\242\347\273\230\345\210\266\345\244\232\345\261\202\347\272\247\350\241\250\346\240\274.md" index 297a5f5..6ec04f2 100644 --- "a/content/post/Development/JavaScript/\346\265\213\350\257\225\347\273\223\346\236\234\346\212\245\350\241\250\345\261\225\347\216\260\357\274\232Web\351\241\265\351\235\242\347\273\230\345\210\266\345\244\232\345\261\202\347\272\247\350\241\250\346\240\274.md" +++ "b/content/post/Development/JavaScript/\346\265\213\350\257\225\347\273\223\346\236\234\346\212\245\350\241\250\345\261\225\347\216\260\357\274\232Web\351\241\265\351\235\242\347\273\230\345\210\266\345\244\232\345\261\202\347\272\247\350\241\250\346\240\274.md" @@ -14,7 +14,7 @@ tags: 很自然地,我们会想到采用如下形式展现对比结果。 -![render table three levels](/images/render_table_three_levels.png) +![render table three levels](/image/render_table_three_levels.png) 图1 三层表格 对应地,采用如下数据结构存储结果数据。 @@ -55,7 +55,7 @@ data_hash = { 为了简化问题分析过程,先尝试对两层表格进行绘制。 -![render table two levels](/images/render_table_two_levels.png) +![render table two levels](/image/render_table_two_levels.png) 图2 两层表格 简化后的数据结构如下: diff --git "a/content/post/Development/Jenkins/Jenkins\347\232\204\350\276\223\345\207\272\346\227\245\345\277\227\344\271\237\345\217\257\344\273\245\345\217\230\345\276\227\350\211\262\350\211\262\347\232\204.md" "b/content/post/Development/Jenkins/Jenkins\347\232\204\350\276\223\345\207\272\346\227\245\345\277\227\344\271\237\345\217\257\344\273\245\345\217\230\345\276\227\350\211\262\350\211\262\347\232\204.md" index ba037b5..b33f493 100644 --- "a/content/post/Development/Jenkins/Jenkins\347\232\204\350\276\223\345\207\272\346\227\245\345\277\227\344\271\237\345\217\257\344\273\245\345\217\230\345\276\227\350\211\262\350\211\262\347\232\204.md" +++ "b/content/post/Development/Jenkins/Jenkins\347\232\204\350\276\223\345\207\272\346\227\245\345\277\227\344\271\237\345\217\257\344\273\245\345\217\230\345\276\227\350\211\262\350\211\262\347\232\204.md" @@ -22,7 +22,7 @@ tags: 安装完成后,在Jenkins Project的`Configure`页面中,`Build Environment`栏目下会多出`Color ANSI Console Output`配置项,勾选后即可开启颜色输出配置。 -![Jenkins Color ANSI Console Output](/images/Jenkins_Color_ANSI_Console_Output.jpg) +![Jenkins Color ANSI Console Output](/image/Jenkins_Color_ANSI_Console_Output.jpg) 在`ANSI color map`的列表选择框中,存在多个选项,默认情况下,选择`xterm`即可。 @@ -32,7 +32,7 @@ tags: 使用`xctool`命令编译iOS应用时,在Jenkins的`Console output`中会看到和`Terminal`中一样的颜色效果。 -![Jenkins Console Output Colored](/images/Jenkins_Console_Output_Colored.jpg) +![Jenkins Console Output Colored](/image/Jenkins_Console_Output_Colored.jpg) ## 补充说明 @@ -119,6 +119,6 @@ puts step_action_desc.red 展示效果如下图所示。 -![Terminal Output Colored](/images/Terminal_Output_Colored.jpg) +![Terminal Output Colored](/image/Terminal_Output_Colored.jpg) 是不是好看多了? diff --git "a/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\346\214\201\347\273\255\351\233\206\346\210\220\346\236\204\345\273\272\346\243\200\346\237\245.md" "b/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\346\214\201\347\273\255\351\233\206\346\210\220\346\236\204\345\273\272\346\243\200\346\237\245.md" index 9e3ba95..8124d2e 100644 --- "a/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\346\214\201\347\273\255\351\233\206\346\210\220\346\236\204\345\273\272\346\243\200\346\237\245.md" +++ "b/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\345\256\236\347\216\260\346\214\201\347\273\255\351\233\206\346\210\220\346\236\204\345\273\272\346\243\200\346\237\245.md" @@ -76,15 +76,15 @@ $ ruby run.rb -p "${OUTPUT_FOLDER}/${SCHEME}.app.zip" --disable_output_color > t 安装完该插件后,在Jenkins配置界面的`Post-build Actions`栏目中,`Add post-build action`选项列表中就会多出`Execute a set of scripts`选项。选择该项后,会出现如下配置界面。 -![Jenkins Post_build_Actions Execute_shell menu](/images/Jenkins_Post_build_Actions_Execute_shell_menu.jpg) +![Jenkins Post_build_Actions Execute_shell menu](/image/Jenkins_Post_build_Actions_Execute_shell_menu.jpg) 选择`Execute shell`后,会出现一个文本框,然后我们就可以将构建检查的命令填写到里面。 -![Jenkins Post_build_Actions Execute_shell](/images/Jenkins_Post_build_Actions_Execute_shell.jpg) +![Jenkins Post_build_Actions Execute_shell](/image/Jenkins_Post_build_Actions_Execute_shell.jpg) 在这里我们用到了`${AppiumBooster_Folder}`参数,该参数也需要通过`String Parameter`来进行定义,用于指定`AppiumBooster`项目的路径。 -![Jenkins String Parameter](/images/Jenkins_String_Parameter.jpg) +![Jenkins String Parameter](/image/Jenkins_String_Parameter.jpg) 最后,为了便于将执行自动化测试用例的日志和执行构建的日志分开,我们将执行自动化测试用例的日志写入到了`test_result.log`文件中。然后,在`Archives build artifacts`中就可以通过`${AppiumBooster_Folder}/test_result.log`将执行构建检查的日志收集起来,并展示到每次构建的页面中。 diff --git "a/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\346\220\255\345\273\272\bAPP\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260.md" "b/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\346\220\255\345\273\272\bAPP\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260.md" index c0131bb..d907a67 100644 --- "a/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\346\220\255\345\273\272\bAPP\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260.md" +++ "b/content/post/Development/Jenkins/\344\275\277\347\224\250Jenkins\346\220\255\345\273\272\bAPP\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260.md" @@ -17,8 +17,8 @@ tags: 首先,先给大家展示下平台建设完成后的整体效果: -![Overview of Jenkins Job](/images/Jenkins_Job_Overview.jpg) -![Build view of Jenkins Job](/images/Jenkins_Job_Build_View.jpg) +![Overview of Jenkins Job](/image/Jenkins_Job_Overview.jpg) +![Build view of Jenkins Job](/image/Jenkins_Job_Build_View.jpg) 该平台主要实现的功能有3点: diff --git "a/content/post/Development/Jenkins/\345\205\263\344\272\216\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260\347\232\204Jenkins\351\205\215\347\275\256\345\222\214\346\236\204\345\273\272\350\204\232\346\234\254\345\256\236\347\216\260\347\273\206\350\212\202.md" "b/content/post/Development/Jenkins/\345\205\263\344\272\216\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260\347\232\204Jenkins\351\205\215\347\275\256\345\222\214\346\236\204\345\273\272\350\204\232\346\234\254\345\256\236\347\216\260\347\273\206\350\212\202.md" index 5bbb71c..c372c73 100644 --- "a/content/post/Development/Jenkins/\345\205\263\344\272\216\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260\347\232\204Jenkins\351\205\215\347\275\256\345\222\214\346\236\204\345\273\272\350\204\232\346\234\254\345\256\236\347\216\260\347\273\206\350\212\202.md" +++ "b/content/post/Development/Jenkins/\345\205\263\344\272\216\346\214\201\347\273\255\351\233\206\346\210\220\346\211\223\345\214\205\345\271\263\345\217\260\347\232\204Jenkins\351\205\215\347\275\256\345\222\214\346\236\204\345\273\272\350\204\232\346\234\254\345\256\236\347\216\260\347\273\206\350\212\202.md" @@ -228,7 +228,7 @@ $ python ${WORKSPACE}/Build_scripts/build.py \ 配置完成后,就可以在`Build with Parameters`中通过如下形式手动触发构建。 -![Jenkins manul build](/images/Jenkins_manul_build.jpg) +![Jenkins manul build](/image/Jenkins_manul_build.jpg) ### 2、修改build名称 @@ -244,13 +244,13 @@ Jenkins默认不支持`BuildName`设置,但可通过安装`build-name-setter` 然后再说下如何在`Build History`列表中展示每次构建对应的二维码图片。 -![Jenkins build history](/images/Jenkins_build_history.jpg) +![Jenkins build history](/image/Jenkins_build_history.jpg) 需要说明的是,在上图中,绿色框对应的内容是`BuildName`,我们可以通过`build-name-setter`插件来实现自定义配置;但是红色框已经不在`BuildName`的范围之内,而是对应的`BuildDescription`。 同样地,Jenkins默认不支持在构建过程中自动修改`BuildDescription`,需要通过安装`description setter plugin`插件来辅助实现。安装`description setter plugin`插件后,在配置页面的`Build`栏目下,`Add build step`中会出现`Set build description`配置项,添加该配置项后就会出现如下配置框。 -![Jenkins set build description](/images/Jenkins_set_build_description.jpg) +![Jenkins set build description](/image/Jenkins_set_build_description.jpg) 该功能的强大之处在于,它可以在构建日志中通过正则表达式来匹配内容,并将匹配到的内容添加到`BuildDescription`中去。 @@ -288,7 +288,7 @@ appDownloadPage: (.*)$ 添加后的配置页面如下图所示: -![Jenkins archive the artifacts](/images/Jenkins_archive_the_artifacts.jpg) +![Jenkins archive the artifacts](/image/Jenkins_archive_the_artifacts.jpg) 通常,我们只需要配置`Files to archive`即可。定位文件时,可以通过正则表达式进行匹配,也可以调用项目的环境变量;多个文件通过逗号进行分隔。 @@ -302,7 +302,7 @@ ${OUTPUT_FOLDER}/*.ipa,${OUTPUT_FOLDER}/QRCode.png,${OUTPUT_FOLDER}/*.xcarchive/ 通过这种方式,我们就可以实现在每次完成构建后将需要的文件收集起来进行存档,以便后续在Jenkins的任务页面中进行下载。 -![show artifacts of Jenkins](/images/Jenkins_show_artifacts.jpg) +![show artifacts of Jenkins](/image/Jenkins_show_artifacts.jpg) 也可以直接通过归档文件的URL进行访问。例如,上图中`QRCode.png`的URL为`Jenkins_Url/job/JenkinsJobName/131/artifact/build_outputs/QRCode.png`,而`Jenkins_Url/job/JenkinsJobName/131/`即是`${BUILD_URL}`,因此可以直接通过`${BUILD_URL}artifact/build_outputs/QRCode.png`引用。 diff --git "a/content/post/Development/Jenkins/\351\200\232\350\277\207API\350\277\234\347\250\213\347\256\241\347\220\206Jenkins.md" "b/content/post/Development/Jenkins/\351\200\232\350\277\207API\350\277\234\347\250\213\347\256\241\347\220\206Jenkins.md" index 4527c9c..bd3c2f5 100644 --- "a/content/post/Development/Jenkins/\351\200\232\350\277\207API\350\277\234\347\250\213\347\256\241\347\220\206Jenkins.md" +++ "b/content/post/Development/Jenkins/\351\200\232\350\277\207API\350\277\234\347\250\213\347\256\241\347\220\206Jenkins.md" @@ -14,7 +14,7 @@ tags: 为了更好地说明问题,在下图中展示了一个精简的持续集成测试系统。 -![Jenkins DroidTestbed](/images/Jenkins-DroidTestbed.png) +![Jenkins DroidTestbed](/image/Jenkins-DroidTestbed.png) 在该系统中,Jenkins负责定时检测代码库(`Code Repository`)的代码更新情况,当检测到有新的代码提交时,自动采用最新的代码进行构建,并采用构建得到的包(apk)触发自动化测试平台(`DroidTestbed`)执行测试任务。 @@ -137,7 +137,7 @@ Jenkins的Remote API以`REST-like`的形式进行提供,通过对特定的API 先看下整体的系统架构图。 -![DroidTestbed DroidMeter](/images/DroidTestbed-DroidMeter.png) +![DroidTestbed DroidMeter](/image/DroidTestbed-DroidMeter.png) 整个系统实现的功能是Android App的性能持续集成测试平台,主要由`DroidTestbed`和`DroidMeter`两部分组成。 diff --git "a/content/post/Development/ToolsNotes/\345\246\202\344\275\225\344\274\230\351\233\205\345\234\260\344\270\200\351\224\256\345\256\236\347\216\260macOS\347\275\221\347\273\234\344\273\243\347\220\206\345\210\207\346\215\242.md" "b/content/post/Development/ToolsNotes/\345\246\202\344\275\225\344\274\230\351\233\205\345\234\260\344\270\200\351\224\256\345\256\236\347\216\260macOS\347\275\221\347\273\234\344\273\243\347\220\206\345\210\207\346\215\242.md" index 6ce16f0..0885ebe 100644 --- "a/content/post/Development/ToolsNotes/\345\246\202\344\275\225\344\274\230\351\233\205\345\234\260\344\270\200\351\224\256\345\256\236\347\216\260macOS\347\275\221\347\273\234\344\273\243\347\220\206\345\210\207\346\215\242.md" +++ "b/content/post/Development/ToolsNotes/\345\246\202\344\275\225\344\274\230\351\233\205\345\234\260\344\270\200\351\224\256\345\256\236\347\216\260macOS\347\275\221\347\273\234\344\273\243\347\220\206\345\210\207\346\215\242.md" @@ -13,7 +13,7 @@ tags: 在`macOS`中配置Web代理时,通常的做法是在控制面板中进行操作,`System Preferences` -> `Network` -> `Advanced` -> `Proxies`. -![macOS-Web-Proxy-Setting](/images/macOS-Web-Proxy-Setting.jpg) +![macOS-Web-Proxy-Setting](/image/macOS-Web-Proxy-Setting.jpg) 这种配置方式虽然可以实现需求,但缺点在于操作比较繁琐,特别是在需要频繁切换的情况下,效率极其低下。 @@ -117,7 +117,7 @@ $ echo | sudo -S networksetup -setwebproxystate 'Wi-Fi' off && sudo n 配置十分简洁清晰,不用解释也能看懂。完成配置后,在`macOS`顶部菜单栏中就会出现如下效果的快捷方式。 -![macOS-Web-Proxy-Setting](/images/shuttle-preview.png) +![macOS-Web-Proxy-Setting](/image/shuttle-preview.png) 后续,我们就可以通过快捷方式实现一键切换HTTP(S)代理配置、一键启动`mitmproxy`抓包工具了。 diff --git "a/content/post/Development/ToolsNotes/\346\225\217\346\215\267\345\233\242\351\230\237\345\215\217\344\275\234\357\274\232Confluence\347\256\200\346\230\223\346\225\231\347\250\213.md" "b/content/post/Development/ToolsNotes/\346\225\217\346\215\267\345\233\242\351\230\237\345\215\217\344\275\234\357\274\232Confluence\347\256\200\346\230\223\346\225\231\347\250\213.md" index e821133..869a5d2 100644 --- "a/content/post/Development/ToolsNotes/\346\225\217\346\215\267\345\233\242\351\230\237\345\215\217\344\275\234\357\274\232Confluence\347\256\200\346\230\223\346\225\231\347\250\213.md" +++ "b/content/post/Development/ToolsNotes/\346\225\217\346\215\267\345\233\242\351\230\237\345\215\217\344\275\234\357\274\232Confluence\347\256\200\346\230\223\346\225\231\347\250\213.md" @@ -66,11 +66,11 @@ Confluence内置了大量的模板,可辅助用于项目工作的各个环节 创建空间的方式很简单,可以从顶部菜单进行创建:【Spaces】->【Create Space】;也可以从Dashboard页面的Spaces页面中进行创建。 -![Confluence Dashboard](/images/Confluence_Dashboard.png) +![Confluence Dashboard](/image/Confluence_Dashboard.png) 进入创建空间页面后,需要选择空间类型。这个需要根据空间的用途进行选择,对于团队协作的空间,推荐选择“Team Space”,如果实在不知道选择什么类型,选择“Blank Space”也是可以的。 -![Create space in Confluence](/images/Confluence_Create_Space.png) +![Create space in Confluence](/image/Confluence_Create_Space.png) 然后是填写空间的基本信息。所有类型的空间都有两个必填字段,Space name和Space key。Space key可以理解为空间的ID,不同空间的Space key不能重复,但Space name是可以重复的。 @@ -78,7 +78,7 @@ Confluence内置了大量的模板,可辅助用于项目工作的各个环节 需要说明的是,空间创建完成后,Space key字段是不能修改的,其它字段以及团队成员都可以进行修改。 -![Create team space in Confluence](/images/Confluence_Create_Team_Space.png) +![Create team space in Confluence](/image/Confluence_Create_Team_Space.png) ### 配置空间权限 @@ -86,11 +86,11 @@ Confluence内置了大量的模板,可辅助用于项目工作的各个环节 操作方式如下:首先进入空间的页面,在空间左下角中,【Space tools】->【Permissions】,进入权限管理页面。 -![Permissions menu of Confluence](/images/Confluence_Permissions_menu.png) +![Permissions menu of Confluence](/image/Confluence_Permissions_menu.png) Confluence的权限控制比较完善,可以根据团队规范进行较为精细粒度的设置。 -![Permissions settings of Confluence](/images/Confluence_Permissions_Setting.png) +![Permissions settings of Confluence](/image/Confluence_Permissions_Setting.png) ### 添加文档 @@ -98,7 +98,7 @@ Confluence的权限控制比较完善,可以根据团队规范进行较为精 推荐的创建方式是,先进入父目录的页面,然后再点击【Create】进行创建。在创建文档页面中,可以看到新建文档的“Parent”,表示新文档创建后将位于“Parent”文件的下一个层级中。 -![Create page in Confluence](/images/Confluence_Create_Page.png) +![Create page in Confluence](/image/Confluence_Create_Page.png) 在新建文档时,需要选择文档模板。这个就根据文档的实际类型或用途进行选择即可,如果觉得都不合适,就选择“Blank page”。 @@ -108,7 +108,7 @@ Confluence的权限控制比较完善,可以根据团队规范进行较为精 Confluence也集成了许多编辑工具,可以很方便地插入图表、链接、附件、代办列表等等。如果还不满足需求,可以点击【Insert】->【Other macros】,查找更多的扩展插件。 -![Edit page of Confluence](/images/Confluence_Edit_Page.png) +![Edit page of Confluence](/image/Confluence_Edit_Page.png) 例如,Confluence默认是不支持Markdown编辑模式的,如果想采用Markdown来编写文档,就可以通过上述方式到插件市场寻找Markdown的插件。 @@ -120,8 +120,8 @@ Confluence也集成了许多编辑工具,可以很方便地插入图表、链 操作方式如下:先进入到待移动的文档页面中,点击页面右上角的【...】->【Move】; -![Move page menu of Confluence](/images/Confluence_Move_Page_menu.png) +![Move page menu of Confluence](/image/Confluence_Move_Page_menu.png) 然后选择新的目录即可。 -![Move page of Confluence](/images/Confluence_Move_Page.png) +![Move page of Confluence](/image/Confluence_Move_Page.png) diff --git "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2018 \345\271\264\347\273\210\346\200\273\347\273\223.md" "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2018 \345\271\264\347\273\210\346\200\273\347\273\223.md" index 7f2953a..574d8ee 100644 --- "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2018 \345\271\264\347\273\210\346\200\273\347\273\223.md" +++ "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2018 \345\271\264\347\273\210\346\200\273\347\273\223.md" @@ -32,7 +32,7 @@ tags: 今年与小坚果一起度过了两个重要的日子。一个是他满百天的时候,当时带着他第一次回到了我的老家,办了一个百天宴,也让我的爷爷奶奶第一次抱上了曾孙,两位老人异常高兴,一大家人久违地聚在了一起,拍了四世同堂的全家福,非常圆满。另一个就是在他满一周岁的时候,给他在深圳公租房家里办了一个生日 Party,当时我妈从重庆过来了,也来了许多朋友和邻居,很是热闹。当时在生日 Party 上,老婆让我讲几句,我酝酿了下,终究没有讲出来。其实我想说,感谢小坚果的到来,我非常幸福,也非常自豪;此生我一定会做一个好爸爸,陪伴小坚果健康快乐成长。 -![](/images/xiaojianguo.jpg) +![](/image/xiaojianguo.jpg) 一口气唠叨了这么多小坚果的点点滴滴,还这么煽情,这些在我当爸爸之前都是完全不敢想象的。 diff --git "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2019 \345\271\264\347\273\210\346\200\273\347\273\223.md" "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2019 \345\271\264\347\273\210\346\200\273\347\273\223.md" index 8ebcafe..188f3e4 100644 --- "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2019 \345\271\264\347\273\210\346\200\273\347\273\223.md" +++ "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2019 \345\271\264\347\273\210\346\200\273\347\273\223.md" @@ -54,7 +54,7 @@ tags: 这一年,小坚果满两岁了,随着他的语言能力越来强,我们的生活也多了许多趣味。例如在我早上要出门上班的时候,他会不舍地拉着我说“不上班”,或者说要“跟爸爸一起去上班”;我安慰他说过两天周末了我们就出去玩,问他到时候想去哪里玩,结果他的要求总是那么低,不是“玩沙沙”就是“找个有滑滑梯的公园玩”。我也沾了小坚果的光,这一年没有以前那么宅了,深圳大点的公园、景点基本上都去了个遍,深圳湾公园都不知道去了多少次。坚果妈在家的时候,他就经常嚷着要“接爸爸下班”;到了来福士,他会在办公区安全闸口候着我,有时候我有点事儿耽误了会儿,他就会跟他妈妈念叨,“怎么还没出来哦”,待看到我后就会冲上来让我抱,这也是我最幸福的时光。小坚果的记忆力也是惊人,很久前去过的地方、吃过的东西,他居然也会记得;有次我在读三字经,发现他居然可以接下句,于是我试着让他来背,发现他居然可以从“人之初”背到“贵以专”,着实令我惊叹不已。当然,这是小坚果乖的时候,调皮捣蛋起来也是忍不住想捶他得不得了。在家里经常把东西翻得到处都是,有时候故意把垃圾桶推倒然后就跑,还“嘎嘎嘎”地笑得特别有成就感。说到这儿又是气,高铁上在我用手机写这份年终总结的时候,他趁我不注意扑过来抢我手机乱点了几下,害得我丢了好多内容(在 apple notes 上没有版本回退)。跟小坚果的点点滴滴太多了,坚果妈在他两岁生日的时候写了一篇,[《来,我们一起》][9],满满的温馨回忆。 -![](/images/xjg-2-birthday.jpeg) +![](/image/xjg-2-birthday.jpeg) 从大疆离职后,我就告别了大疆的公租房福利,开始在外面租房了,这也是我第一次自行在深圳租房。为了上班方便,以及享受字节跳动的租房补贴福利,我就租在了公司旁边,走路十分钟的样子。怎么说呢,住得近也是有好有坏吧。好的方面,不用任何交通工具,每天在路上的时间非常短,再加上公司上班时间晚,因此我基本上都是睡到自然醒,差不多 9:40 才出门去公司(因为公司的早饭 10 点停止供应)。但也是住得太近,感觉就没有了上下班的感觉(俗称仪式感),基本上工作日就是两点一线,不是在公司上班就是在家睡觉,仿佛回到了中学住校的时候。有时候我甚至挺怀念之前开车上下班的时光,在开车的同时还能听下极客时间,而现在这个场景也彻底没了。 diff --git "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2020 \345\271\264\347\273\210\346\200\273\347\273\223.md" "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2020 \345\271\264\347\273\210\346\200\273\347\273\223.md" index 2303c57..8234a23 100644 --- "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2020 \345\271\264\347\273\210\346\200\273\347\273\223.md" +++ "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2020 \345\271\264\347\273\210\346\200\273\347\273\223.md" @@ -24,7 +24,7 @@ tags: 除了提升性能验收的效率外,当时还有一项重点工作是保障飞书第一家私有化部署的客户小米集团完成验收交付,我也自然地成为了一个「苦逼」乙方,需要对接小米 QA 部门及时响应甲方爸爸的各种需求。当时有一个比较有意思的插曲,就是小米 QA 部门必须要求获取接口信息以便他们自己能进行压测验证,否则就不给验收通过(这个要求不过分);字节的安全部门要求不能对外提供接口信息,安全高于一切(这个要求也很合理)。而我们作为业务部门夹在中间就很头疼了,两边都很强势都没有商量的余地,那我们到底要怎么做才能在遵守公司安全合规要求的前提下满足客户的需求,消除合同风险呢?事实证明,办法总比困难多。最终经过探索实践,我基于开源的 Locust + Boomer 封装了一套私有化压测工具,在无需对已有的 golang 压测脚本做调整的情况下,将压测脚本和压测工具整体编译生成一个可执行的二进制文件,再经过安全加固后交付给小米 QA 部门;他们无需再编写压测脚本(也无法获取接口参数细节),最多只需要在配置文件里面调整下接口的流量比例,即可通过一条命令将压测工具进行启动,然后在 Locust Web 界面里面进行压测验证工作。这套方案很好地满足了客户需求,也被顺利地推广到了其它 ToB 业务线(People);我也收获到了比较多的认可,包括加薪和 Spot Bonus 奖励,也算得上是一个 happy ending 了。 -![](/images/feishu-spot-bonus.png) +![](/image/feishu-spot-bonus.png) ### 转岗经历 @@ -40,7 +40,7 @@ tags: 转岗到互娱研发后,首先非常震惊的是 QA 部门很大,内部方向也很多。为了帮助我快速了解整体情况,HY 特别有心地帮我联系了各个方向的负责人,然后让我出差到北京、上海、杭州等城市跟各方向负责人当面聊了一遍,熟悉业务的同时也混个脸熟。具体工作方向方面,虽然 IES 在成都的业务方向是抖音 S 业务,但测试开发相对独立,不局限于抖音 S 业务。当时给我的自由度也很高,可以跟着 HY 一起做国际化机架相关的,也可以找新的独立方向。从发展前景来看,单独立新的方向可能会有更多的机会,但经过短暂的考虑后,我还是决定加入 HY 的专项测试团队一起做国际化机架项目。原因很简单,一个是之前跟 HY 团队已经有过密切的合作,他们在做的国际化机架项目具有很多有挑战的点,能满足我个人的技术成长诉求;另一个原因就是在跟HY团队初步接触后,被他们的热情给深深打动了,跟团队成员相处也很融洽。下图是刚转岗时HY拉的一个关怀群,让各个子方向的 owner 帮助我快速融入。 -![](/images/enroll-team.png) +![](/image/enroll-team.png) ### 抖音(成都) @@ -58,7 +58,7 @@ tags: 目标明确后,离开深圳时心情格外的轻松,下图是自驾离开深圳,途径前海收费站发的朋友圈。当时我老婆也在她的公众号发了一篇文章,《[在告别深圳的路上,我说成都的夕阳也那么美,你说是的][2]》,里面也记录了很多我们在深圳的美好回忆。 -![](/images/bye-shenzhen.png) +![](/image/bye-shenzhen.png) 在文章开头说到,转岗到成都后,工作内容和节奏没太大变化,但生活质量和幸福感得到了极大的提升。 @@ -72,7 +72,7 @@ tags: 这一年,小坚果也有了不少改变。他的性格一直都很温和,不争不抢的,玩具被其它小朋友拿走后也默不作声(内心可能也会很难过);但坚果妈告诉他,如果心里不情愿的话,就要勇敢拒绝,守卫自己的东西;结果他后面在被大哥哥抢玩具的时候,还真的硬刚,把玩具抢回来了。哦对了,他的数数能力也增长了很多。早上上班前我经常会跟他玩一会儿火车轨道之类的游戏,为了能顺利出门,就会让他自己说还要玩几圈。以前他只会说三圈,四圈;后来估计是长记性了,就会说 14 圈,甚至 60 圈,越来越不好忽悠了😂。 -![](/images/xjg-3.jpeg) +![](/image/xjg-3.jpeg) ## 成长 & 思考 diff --git "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2021 \345\271\264\347\273\210\346\200\273\347\273\223.md" "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2021 \345\271\264\347\273\210\346\200\273\347\273\223.md" index ebdc45e..1e07968 100644 --- "a/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2021 \345\271\264\347\273\210\346\200\273\347\273\223.md" +++ "b/content/post/Growth/\345\271\264\347\273\210\346\200\273\347\273\223/\346\210\221\347\232\204 2021 \345\271\264\347\273\210\346\200\273\347\273\223.md" @@ -60,7 +60,7 @@ tags: 下图罗列了 HttpRunner+ 从 9 月开始开发至今已经实现的功能特性,以及近期要完成的重点功能特性。可以看出,当前 golang 版的 hrp 已经在功能上基本追平了 Python 版的 HttpRunner,并且在性能测试方向增加了许多 locust/boomer 缺失的特性。 -![](/images/hrp-2021.png) +![](/image/hrp-2021.png) 限于本文重点,这里就不再对 HttpRunner+ 进行过多介绍了,接下来我将会重点补齐用户文档后,再通过多个渠道进行下宣传介绍,后续也将加强下针对 HttpRunner+ 的运营和用户支持。 @@ -123,7 +123,7 @@ tags: 今年小坚果开始去上幼儿园了。刚开始他还挺开心的,但上了一段时间后,他就不怎么喜欢去幼儿园了。问他为什么,他就说「幼儿园就是吃东西和睡觉,也不学习,一点都不好玩,要不是可以挣钱都不想去了」。原来他一直以为自己去上幼儿园就跟我去上班一样,是可以挣钱的。哈哈,这么小就展现出学霸潜质了,还知道为家里分担负担了。 -![](/images/xjg-2021.jpeg) +![](/image/xjg-2021.jpeg) ### 小云朵 diff --git "a/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\345\206\231\345\234\250\345\244\247\347\226\206\346\257\225\344\270\232\344\271\213\351\231\205.md" "b/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\345\206\231\345\234\250\345\244\247\347\226\206\346\257\225\344\270\232\344\271\213\351\231\205.md" index 843f1bd..842a6f4 100644 --- "a/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\345\206\231\345\234\250\345\244\247\347\226\206\346\257\225\344\270\232\344\271\213\351\231\205.md" +++ "b/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\345\206\231\345\234\250\345\244\247\347\226\206\346\257\225\344\270\232\344\271\213\351\231\205.md" @@ -165,7 +165,7 @@ tags: 最后,真心祝愿大疆越来越好,各位领导和同事一切顺利! -![](/images/dji-graduated.jpeg) +![](/image/dji-graduated.jpeg) [1]: https://debugtalk.com/post/my-2018-summary/ \ No newline at end of file diff --git "a/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\346\230\245\350\212\202\346\227\205\350\241\214\344\271\213\346\204\217\346\263\225\345\215\260\350\261\241.md" "b/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\346\230\245\350\212\202\346\227\205\350\241\214\344\271\213\346\204\217\346\263\225\345\215\260\350\261\241.md" index 9eec5c3..8bd5d4b 100644 --- "a/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\346\230\245\350\212\202\346\227\205\350\241\214\344\271\213\346\204\217\346\263\225\345\215\260\350\261\241.md" +++ "b/content/post/Growth/\346\200\235\350\200\203 & \346\204\237\346\202\237/\346\230\245\350\212\202\346\227\205\350\241\214\344\271\213\346\204\217\346\263\225\345\215\260\350\261\241.md" @@ -9,7 +9,7 @@ tags: - 思考记录 --- -![](/images/Florence1.jpg) +![](/image/Florence1.jpg) 今年春节没有像往常一样回家过年,而是到欧洲旅行(意大利和法国),算是蜜月游吧。第一次到欧洲,确切地说,第一次出国,新鲜感还是蛮大的,趁着返程飞机上的空闲时间,写篇博客记录下。 @@ -17,19 +17,19 @@ tags: 先说下总体印象吧。如果说要通过几个关键词来概括这次旅行的所见所闻,特别是跟国内(一二线城市)进行对比的话,我个人的印象是:自然环境优美、生活节奏舒缓、饮食类型单一、公共设施陈旧、公共安全紧张、工程师氛围稀缺。 -![](/images/Florence2.jpg) +![](/image/Florence2.jpg) 自然环境优美没啥好说的,之前不管是通过网络,还是和朋友的聊天交流,对欧洲的印象就是自然环境特别好。实际情况也的确是这样的。空气质量这块儿我没啥特别的感觉,因为深圳的空气本来也挺好的。见过的河水湖泊很是清澈,完全没有污染的痕迹。绿化非常赞,除了街道的树木,在城市中有很多森林公园。印象最深的就是小动物了,虽然是在城市里,但是到处都能看到鸽子、海鸥,在公园里还能看到野鸡、野鸭、天鹅,而且好玩的是这些动物基本都不怕人,靠近它们的时候也不会躲避,我还趁天鹅把头钻进水里捕食时偷偷摸了它的屁股。想想在国内,能在城市中看见只麻雀就算稀罕了,这方面真是没法比。 在人文环境方面,最大的感触就是欧洲的生活节奏十分舒缓。店铺通常开得挺晚的,关得也特别早,特别是在罗马和佛罗伦萨,下午六七点天黑后,就基本很少看到人了。在我等天朝IT狗的眼里,他们的工作量真是极其的不饱和啊。可能也是这方面的原因,商家普遍的服务态度都挺好的,很有耐心。有一次在梵蒂冈的礼品店里,虽然语言交流不是很顺畅,但老太太还是很有耐心的一一介绍,最后由于感觉价格比较贵,不大好意思地说不买了,老太太也完全没有表现出任何不悦,而是笑盈盈地说了句`Thank you, have a nice day`。在欧洲街道上,如果是在没有红绿灯的情况下,司机都会挥手示意让行人先过马路。刚开始的时候还有些不习惯,站在路口等汽车先走,结果司机更有耐心,执意等行人先走。哦对,在欧洲马路上,基本上没有听到汽车喇叭声,有时候没有看到身后的车辆,司机会探出头来打招呼。另外,在欧洲街头经常会看见各种行为艺术,特别是在罗马斗兽场的一条街道上,一路走去,吹拉弹唱跳,形式各异,水准颇高,真是一道靓丽的风景。看到他们总会经不住感叹,人家这才是生活啊,我等只能叫活着。 -![](/images/Pisa.jpg) +![](/image/Pisa.jpg) 说到语言交流,这跟我之前的预期不大一样。在没出国之前,原以为欧洲的英语应该普及度很高,结果到了这边后发现并非如此,好多本地人并不会英语,即使是警察这样的公务员,会说英语的也是少数,而且口音还特别重。不过语言也真是一个神奇的东西,可能同样的场景,做英语听力理解题时无法正确答题,但是在面对面交流时,加上简单的肢体动作和眼神,基本上只要不是太复杂的场景,都难很好的完成交流。最多为了保险起见,我再用英语复述一遍我的理解,跟对方进行确认即可。哦对了,在欧洲遇到的好多人虽然不会说英语,但是貌似听懂是没啥问题,只是可能有些词汇不理解,需要变换下说法。例如,在询问能不能飞无人机时,跟他们说`drone`他们都不知道是啥意思,但是说`mini aircraft`他们就会明白了。 然后说下差异最大的饮食吧。跟博大精深的中餐相比,欧洲的饮食真是单一乏味。当然,像法餐这样高逼格的不在讨论范围内,价格太贵,我相信即使是本地人也不至于天天这么吃吧。在意大利和法国,当地人吃得最多的应该就是披萨和汉堡了。在我看来,意大利人真是除了披萨意面就没啥别的了。虽然披萨被做出花儿了,各种馅儿的都有,但老是这么吃还是受不了。意面更别提了,我们吃了一次就不想再吃。有一次在披萨店惊奇地发现有米饭,结果还是半生的,完全没法吃,想想也是,微波炉哪能做出米饭来。因此我们后面每到一个城市,就到处找中餐馆。中餐的价格普遍比披萨店贵两倍,面条、炒饭、盖浇饭这类快餐,普遍在7~9欧的样子,如果点菜的话,人均消费差不多要十多欧,这还是在比较克制的情况下。即使是这样,中餐馆的生意还都特别好。在罗马的一家中餐馆给我们的印象尤其深刻,我们是通过大众点评找过去的,结果到了以后发现门口贴纸告知要五点半开门。我们还以为店家不会开门了,就先在旁边的一家披萨店先吃着。过一会儿后,发现那家店门口逐渐聚集了一波中国人,到了五点半的时候,还真准时开门了。进去之后,发现基本满座了,全是中国人。一会儿后,服务员领班说,要等一阵才能点菜,因为厨师们要先吃饭。然后,所有顾客就看着一大桌厨师和服务员在那儿吃。我们也真是长见识了,原来餐馆还能这么开的,牛逼,换成在国内试试? -![](/images/chocolates.jpg) +![](/image/chocolates.jpg) 除了饮食,公共基础设施方面跟国内也没法比。首先是公交地铁,普遍比叫陈旧。特别是巴黎的`RER`线,简直难以相信这就是号称时尚浪漫之都的巴黎,刷票的门坏了好几个,各种电线暴露在外面垂在半空中,好多通道没有电梯,地铁车厢特别脏,地面积了厚厚的泥土和水渍,估计是好久都没有打扫过了,让我们一度以为我们到了假巴黎。然后说下欧洲的公厕,上一次要1欧,即使是在有的麦当劳店里,上厕所也是要收费的,每次想上厕所时换算下,要七块多人民币,真是尿不起啊有木有!不过公厕收费也比较好理解,因为欧洲的人力成本本来就比较高,特别是清洁工这类工种。除了硬件类的基础设施,软件类的服务跟国内相比也落后太多。在国内的时候,基本上带个手机出门就行了,吃饭、购物、叫车全电子化,但是在欧洲都基本还是用现金,大额消费可以刷信用卡,出去一趟回来兜里就好多找零的硬币。当然,虽然欧洲本土的互联网服务不咋地,但是人家能用`Google`的各项服务啊,光这一项我大天朝就完全被秒杀了。 @@ -43,4 +43,4 @@ tags: > Keep learning and programming. -![](/images/Florence3.jpg) \ No newline at end of file +![](/image/Florence3.jpg) \ No newline at end of file diff --git "a/content/post/Growth/\346\274\224\350\256\262\350\256\260\345\275\225/\346\210\221\347\232\204 MTSC 2019 \345\210\206\344\272\253\347\273\217\345\216\206.md" "b/content/post/Growth/\346\274\224\350\256\262\350\256\260\345\275\225/\346\210\221\347\232\204 MTSC 2019 \345\210\206\344\272\253\347\273\217\345\216\206.md" index 347099a..6bab6b4 100644 --- "a/content/post/Growth/\346\274\224\350\256\262\350\256\260\345\275\225/\346\210\221\347\232\204 MTSC 2019 \345\210\206\344\272\253\347\273\217\345\216\206.md" +++ "b/content/post/Growth/\346\274\224\350\256\262\350\256\260\345\275\225/\346\210\221\347\232\204 MTSC 2019 \345\210\206\344\272\253\347\273\217\345\216\206.md" @@ -22,9 +22,9 @@ tags: 实际在现场分享时,现场来的听众比预期中多了不少,将整个会场塞得满满的,在此也十分感谢大家的关注和支持。而我自己比较出乎意料的是,从头到尾基本上没有紧张的感觉,可能是之前已经有过多次大会分享的经历了吧,也可能是自己心态变好(脸皮变厚)了,想好最坏的结果无非就是现场演示出现意外,然后在一阵“哈哈哈”中拿出事先录制好的演示视频,总不会被轰下去吧。庆幸的是,现场网络环境、被测对象、框架和脚本都很稳定,最终演示也一切顺利。不过时间把控还是没有做好,最后没有剩下时间跟大家 Q&A 互动,颇为遗憾。 -![](/images/MTSC2019-1.jpeg) +![](/image/MTSC2019-1.jpeg) -![](/images/MTSC2019-2.jpeg) +![](/image/MTSC2019-2.jpeg) 现场演示出现小意外时,表情被摄影师捕获到了,😝 @@ -32,7 +32,7 @@ tags: 最后,祝愿 MTSC 越来越好,我们明年再见! -![](/images/MTSC2019-3.jpeg) +![](/image/MTSC2019-3.jpeg) 附录:本次分享的 Keynote [下载链接][keynote]。 diff --git a/content/post/OpenSource/AppiumBooster/Introduction-to-AppiumBooster.md b/content/post/OpenSource/AppiumBooster/Introduction-to-AppiumBooster.md index 62a9621..1f3c1c9 100644 --- a/content/post/OpenSource/AppiumBooster/Introduction-to-AppiumBooster.md +++ b/content/post/OpenSource/AppiumBooster/Introduction-to-AppiumBooster.md @@ -17,7 +17,7 @@ AppiumBooster helps you to write automation testcases in yaml format or csv tabl Take DebugTalk+ Discover's login and logout function as an example. -![preview of login and logout](/images/preview_login_and_logout.png) +![preview of login and logout](/image/preview_login_and_logout.png) In order to test these functions above, you can write testcases in yaml format like this. @@ -79,7 +79,7 @@ You can also write testcases in any table tools, including MS Excel and iWork Nu In order to test the same functions above, you can write testcases in tables like this. -![testcases of login and logout](/images/testcase_login_and_logout.png) +![testcases of login and logout](/image/testcase_login_and_logout.png) After the testcases are finished, export to CSV format, and put the csv files under `ios/testcases/` directory. diff --git "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260 (4)\357\274\232\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\344\273\243\347\240\201\342\216\241\345\267\245\347\250\213\345\214\226\342\216\246.md" "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260 (4)\357\274\232\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\344\273\243\347\240\201\342\216\241\345\267\245\347\250\213\345\214\226\342\216\246.md" index 6dc5ca5..ce3d362 100644 --- "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260 (4)\357\274\232\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\344\273\243\347\240\201\342\216\241\345\267\245\347\250\213\345\214\226\342\216\246.md" +++ "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260 (4)\357\274\232\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\344\273\243\347\240\201\342\216\241\345\267\245\347\250\213\345\214\226\342\216\246.md" @@ -279,7 +279,7 @@ end 那有没有一种可能,我们只需要在表格中维护自动化测试用例(如下图),然后由代码来读取表格内容就可以自动执行测试呢? -![AppiumBooster overview testcase examples](/images/testcase_login_and_logout.png) +![AppiumBooster overview testcase examples](/image/testcase_login_and_logout.png) 是的,这就是我们对测试框架进行⎡工程化⎦改造的下一个形态,也就是[`AppiumBooster`](https://github.com/debugtalk/AppiumBooster)现在的样子。 diff --git "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2100\357\274\211\357\274\232\350\203\214\346\231\257\344\273\213\347\273\215\345\222\214\345\271\263\345\217\260\350\247\204\345\210\222.md" "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2100\357\274\211\357\274\232\350\203\214\346\231\257\344\273\213\347\273\215\345\222\214\345\271\263\345\217\260\350\247\204\345\210\222.md" index 6074465..26541f9 100644 --- "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2100\357\274\211\357\274\232\350\203\214\346\231\257\344\273\213\347\273\215\345\222\214\345\271\263\345\217\260\350\247\204\345\210\222.md" +++ "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2100\357\274\211\357\274\232\350\203\214\346\231\257\344\273\213\347\273\215\345\222\214\345\271\263\345\217\260\350\247\204\345\210\222.md" @@ -19,7 +19,7 @@ tags: 基于当前项目的开发模式,我对整个M项目实现持续集成自动化测试的架构流程进行了规划,初步计划的架构图如下图所示。最终的目标是希望能实现:不管是Rails Server,还是App(iOS/Android),以及H5,当任意部分存在代码提交时,系统能自动拉取最新代码进行部署并执行自动化回归测试,及时地将执行情况反馈给开发人员。 -![](/images/DebugTalk_Plus_Automated_Test_Platform.jpg) +![](/image/DebugTalk_Plus_Automated_Test_Platform.jpg) 目标确定后,便是分阶段进行实现,需要开发的模块包括: diff --git "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2101\357\274\211\357\274\232\346\250\241\346\213\237\345\231\250\344\270\255\350\277\220\350\241\214iOS\345\272\224\347\224\250.md" "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2101\357\274\211\357\274\232\346\250\241\346\213\237\345\231\250\344\270\255\350\277\220\350\241\214iOS\345\272\224\347\224\250.md" index ead8b1e..b0c1326 100644 --- "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2101\357\274\211\357\274\232\346\250\241\346\213\237\345\231\250\344\270\255\350\277\220\350\241\214iOS\345\272\224\347\224\250.md" +++ "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2101\357\274\211\357\274\232\346\250\241\346\213\237\345\231\250\344\270\255\350\277\220\350\241\214iOS\345\272\224\347\224\250.md" @@ -24,7 +24,7 @@ tags: 现在我们想在Appium App中通过模拟器运行被测应用,需要指定iOS app的安装包路径,因此需要首先获得一个iOS app安装包。 -![Appium initialize iOS Settings](/images/Appium_iOS_Settings_init.jpg) +![Appium initialize iOS Settings](/image/Appium_iOS_Settings_init.jpg) 那么iOS app的安装包长啥样呢? @@ -107,11 +107,11 @@ Pod installation complete! There are 27 dependencies from the Podfile and 28 tot 设置完毕后,点击【Launch】,启动`Appium Server`。 -![Appium inspector button](/images/Appium_Inspector_Button.jpg) +![Appium inspector button](/image/Appium_Inspector_Button.jpg) 然后,点击图中红框处的按钮,即可通过`Inspector`启动模拟器,并在模拟器中加载iOS应用。 -![Appium iOS Simulator Console](/images/Appium_iOS_Simulator_Console.jpg) +![Appium iOS Simulator Console](/image/Appium_iOS_Simulator_Console.jpg) 在模拟器中,我们可以像在真机中一样,体验被测应用的各项功能;并且,在Appium的日志台中,可以实时查看到日志信息。 @@ -121,7 +121,7 @@ Pod installation complete! There are 27 dependencies from the Podfile and 28 tot 通过`Inspector`启动模拟器时,总是弹框报错,报错形式如下。 -![Appium Inspector Error](/images/Appium_Inspector_Error.jpg) +![Appium Inspector Error](/image/Appium_Inspector_Error.jpg) 刚开始出现这问题时百思不得其解,因为提示的信息并不明显,Google了好一阵也没找到原因。最后只有详细去看日志信息,才发现问题所在。 @@ -135,7 +135,7 @@ Pod installation complete! There are 27 dependencies from the Podfile and 28 tot 再来看日志中提示的可用设备,发现“iPhone 6”设备对应的`Platform Version`只有“9.2”和“9.3”。然后回到`iOS Settings`,发现`Platform Version`的下拉框可选项就没有“9.2”和“9.3”,最新的一个可选版本也就是“8.4”。 -![Appium iOS Settings bug](/images/Appium_iOS_Settings_bug.jpg) +![Appium iOS Settings bug](/image/Appium_iOS_Settings_bug.jpg) 这应该是`Appium app`的一个bug吧。不过好在`Platform Version`参数虽然是通过下拉框选择,但是也可以在框内直接填写内容。于是我在`Platform Version`设置框内填写为“9.3”,然后再次启动时,发现iOS模拟器就可以正常启动了。 diff --git "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2102\357\274\211\357\274\232\346\223\215\344\275\234iOS\345\272\224\347\224\250\347\232\204\346\216\247\344\273\266.md" "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2102\357\274\211\357\274\232\346\223\215\344\275\234iOS\345\272\224\347\224\250\347\232\204\346\216\247\344\273\266.md" index 51fb72a..70b161e 100644 --- "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2102\357\274\211\357\274\232\346\223\215\344\275\234iOS\345\272\224\347\224\250\347\232\204\346\216\247\344\273\266.md" +++ "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2102\357\274\211\357\274\232\346\223\215\344\275\234iOS\345\272\224\347\224\250\347\232\204\346\216\247\344\273\266.md" @@ -44,7 +44,7 @@ APP的功能自动化测试,简单地来说,就是让功能测试用例自 运行Appium Server,并启动【Inspector】后,整体界面如下图所示。 -![Appium inspector introduction](/images/Appium_inspector_introduction.jpg) +![Appium inspector introduction](/image/Appium_inspector_introduction.jpg) 现对照着这张图对Appium Inspector进行介绍。 diff --git "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2103\357\274\211\357\274\232\347\274\226\345\206\231iOS\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\350\204\232\346\234\254.md" "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2103\357\274\211\357\274\232\347\274\226\345\206\231iOS\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\350\204\232\346\234\254.md" index bfc71d6..95c9dcf 100644 --- "a/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2103\357\274\211\357\274\232\347\274\226\345\206\231iOS\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\350\204\232\346\234\254.md" +++ "b/content/post/OpenSource/AppiumBooster/\344\273\2160\345\210\2601\346\220\255\345\273\272\347\247\273\345\212\250App\345\212\237\350\203\275\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\345\271\263\345\217\260\357\274\2103\357\274\211\357\274\232\347\274\226\345\206\231iOS\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\350\204\232\346\234\254.md" @@ -47,7 +47,7 @@ tags: 对于本次演示的APP来说,登录时需要先进入【My Account】页面,然后点击【Login】进入登录页面,接着在登录页面中输入账号密码后再点击【Login】按钮,完成登录操作。 -![Preview of DebugTalk Plus login](/images/DebugTalk_Plus_Login.jpg) +![Preview of DebugTalk Plus login](/image/DebugTalk_Plus_Login.jpg) 确定了操作路径以后,就可以在`Appium Ruby Console`中依次操作一遍,目的是确保代码能正确地对控件进行操作。 diff --git "a/content/post/OpenSource/AppiumBooster/\346\211\223\351\200\240\345\277\203\347\233\256\344\270\255\347\220\206\346\203\263\347\232\204\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\346\241\206\346\236\266\357\274\210AppiumBooster\357\274\211.md" "b/content/post/OpenSource/AppiumBooster/\346\211\223\351\200\240\345\277\203\347\233\256\344\270\255\347\220\206\346\203\263\347\232\204\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\346\241\206\346\236\266\357\274\210AppiumBooster\357\274\211.md" index 00fcb6f..a4b1581 100644 --- "a/content/post/OpenSource/AppiumBooster/\346\211\223\351\200\240\345\277\203\347\233\256\344\270\255\347\220\206\346\203\263\347\232\204\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\346\241\206\346\236\266\357\274\210AppiumBooster\357\274\211.md" +++ "b/content/post/OpenSource/AppiumBooster/\346\211\223\351\200\240\345\277\203\347\233\256\344\270\255\347\220\206\346\203\263\347\232\204\350\207\252\345\212\250\345\214\226\346\265\213\350\257\225\346\241\206\346\236\266\357\274\210AppiumBooster\357\274\211.md" @@ -195,7 +195,7 @@ Send random text messages: 采用表格来编写测试用例时,只需要在任意表格工具,包括Microsoft Excel、iWork Numbers、WPS等,按照如下形式对测试用例进行描述。 -![AppiumBooster CSV Testcase example](/images/AppiumBooster_CSV_Testcase_example.jpg) +![AppiumBooster CSV Testcase example](/image/AppiumBooster_CSV_Testcase_example.jpg) 然后,将表格内容另存为`CSV`格式的文件,并放置于`testcases`目录中即可。 diff --git "a/content/post/OpenSource/HttpRunner/300\350\241\214Python\344\273\243\347\240\201\346\211\223\351\200\240\347\232\204\345\256\236\347\224\250\346\216\245\345\217\243\346\265\213\350\257\225\346\241\206\346\236\266.md" "b/content/post/OpenSource/HttpRunner/300\350\241\214Python\344\273\243\347\240\201\346\211\223\351\200\240\347\232\204\345\256\236\347\224\250\346\216\245\345\217\243\346\265\213\350\257\225\346\241\206\346\236\266.md" index 7581520..1212de6 100644 --- "a/content/post/OpenSource/HttpRunner/300\350\241\214Python\344\273\243\347\240\201\346\211\223\351\200\240\347\232\204\345\256\236\347\224\250\346\216\245\345\217\243\346\265\213\350\257\225\346\241\206\346\236\266.md" +++ "b/content/post/OpenSource/HttpRunner/300\350\241\214Python\344\273\243\347\240\201\346\211\223\351\200\240\347\232\204\345\256\236\347\224\250\346\216\245\345\217\243\346\265\213\350\257\225\346\241\206\346\236\266.md" @@ -16,7 +16,7 @@ tags: 刚在`coveralls`上看了下[`ApiTestEngine`][ApiTestEngine]框架的[代码统计行数][ApiTestEngine-coveralls],总行数只有268行,还不足300行。 -![](/images/ApiTestEngine-stat-ate.jpg) +![](/image/ApiTestEngine-stat-ate.jpg) 当然,这个行数指的是框架本身的`Python`代码行数,不包括示例注释的行数。从上图可以看出来,`LINES`列是文件总行数,`RELEVANT`列是实际的`Python`代码行数。例如`ate/runner.py`文件,注释的行数是远多于实际代码行数的。 @@ -64,7 +64,7 @@ def parse(self, testcase_template): 另外,如果算上单元测试用例的行数(731行),总的`Python`代码行数能达到1000行的样子。嗯,代码可以精简,但是单元测试覆盖率还是要保证的,不达到90%以上的单元测试覆盖率,真不好意思说自己做了开源项目啊。 -![](/images/ApiTestEngine-stat-all.jpg) +![](/image/ApiTestEngine-stat-all.jpg) 那这不足300行的Python代码,实际实现了哪些功能呢? diff --git "a/content/post/OpenSource/HttpRunner/ApiTestEngine \346\274\224\350\277\233\344\271\213\350\267\257\357\274\2100\357\274\211\345\274\200\345\217\221\346\234\252\345\212\250\357\274\214\346\265\213\350\257\225\345\205\210\350\241\214.md" "b/content/post/OpenSource/HttpRunner/ApiTestEngine \346\274\224\350\277\233\344\271\213\350\267\257\357\274\2100\357\274\211\345\274\200\345\217\221\346\234\252\345\212\250\357\274\214\346\265\213\350\257\225\345\205\210\350\241\214.md" index 9fefdaa..440c8fb 100644 --- "a/content/post/OpenSource/HttpRunner/ApiTestEngine \346\274\224\350\277\233\344\271\213\350\267\257\357\274\2100\357\274\211\345\274\200\345\217\221\346\234\252\345\212\250\357\274\214\346\265\213\350\257\225\345\205\210\350\241\214.md" +++ "b/content/post/OpenSource/HttpRunner/ApiTestEngine \346\274\224\350\277\233\344\271\213\350\267\257\357\274\2100\357\274\211\345\274\200\345\217\221\346\234\252\345\212\250\357\274\214\346\265\213\350\257\225\345\205\210\350\241\214.md" @@ -225,15 +225,15 @@ script: 下图是某次提交代码时的构建结果。 -![](/images/travis-check-result.jpg) +![](/image/travis-check-result.jpg) 另外,我们还可以在`GitHub`项目的`README.md`中添加一个`Status Image`,实时显示项目的构建状态,就像下图显示的样子。 -![](/images/github-readme-travis-status-image.jpg) +![](/image/github-readme-travis-status-image.jpg) 配置方式也是很简单,只需要先在`Travis CI`中获取到项目`Status Image`的URL地址,然后添加到`README.md`即可。 -![](/images/travis-status-image-url.jpg) +![](/image/travis-status-image-url.jpg) ## 为项目添加单元测试覆盖率检查(coveralls) @@ -328,15 +328,15 @@ after_success: 下图是某次提交代码时的覆盖率检查。 -![](/images/coveralls-result.jpg) +![](/image/coveralls-result.jpg) 另外,我们在`GitHub`项目的`README.md`中也同样可以添加一个`Status Image`,实时显示项目的单元测试覆盖率。 -![](/images/github-coveralls-badge.jpg) +![](/image/github-coveralls-badge.jpg) 配置方式也跟之前类似,在[`coveralls`][coveralls]中获取到项目`Status Image`的URL地址,然后添加到`README.md`即可。 -![](/images/coveralls-image-url.jpg) +![](/image/coveralls-image-url.jpg) 最后需要说明的是,项目的单元测试覆盖率只能起到参考作用,没有被单元测试覆盖到的代码我们不能说它肯定有问题,100%覆盖率的代码也并不能保证它肯定没有问题。归根结底,这还是要依赖于单元测试的策略实现,因此我们在写单元测试的时候也要尽可能多地覆盖到各种逻辑路径,以及兼顾到各种异常情况。 diff --git a/content/post/OpenSource/HttpRunner/ApiTestEngine-QuickStart.md b/content/post/OpenSource/HttpRunner/ApiTestEngine-QuickStart.md index ae08740..de4467d 100644 --- a/content/post/OpenSource/HttpRunner/ApiTestEngine-QuickStart.md +++ b/content/post/OpenSource/HttpRunner/ApiTestEngine-QuickStart.md @@ -38,9 +38,9 @@ Before we write testcases, we should know the details of the API. It is a good c For example, the image below illustrates getting token from the sample service first, and then creating one user successfully. -![](/images/ate-quickstart-http-1.jpg) +![](/image/ate-quickstart-http-1.jpg) -![](/images/ate-quickstart-http-2.jpg) +![](/image/ate-quickstart-http-2.jpg) After thorough understanding of the APIs, we can now begin to write testcases. @@ -328,7 +328,7 @@ Reports generated: /Users/Leo/MyProjects/ApiTestEngine/reports/quickstart-demo-r Great! The test case runs successfully and generates a `HTML` test report. -![](/images/ate-quickstart-demo-report.jpg) +![](/image/ate-quickstart-demo-report.jpg) ## Further more diff --git "a/content/post/OpenSource/HttpRunner/ApiTestEngine\351\233\206\346\210\220Locust\345\256\236\347\216\260\346\233\264\345\245\275\347\232\204\346\200\247\350\203\275\346\265\213\350\257\225\344\275\223\351\252\214.md" "b/content/post/OpenSource/HttpRunner/ApiTestEngine\351\233\206\346\210\220Locust\345\256\236\347\216\260\346\233\264\345\245\275\347\232\204\346\200\247\350\203\275\346\265\213\350\257\225\344\275\223\351\252\214.md" index 101037d..1589036 100644 --- "a/content/post/OpenSource/HttpRunner/ApiTestEngine\351\233\206\346\210\220Locust\345\256\236\347\216\260\346\233\264\345\245\275\347\232\204\346\200\247\350\203\275\346\265\213\350\257\225\344\275\223\351\252\214.md" +++ "b/content/post/OpenSource/HttpRunner/ApiTestEngine\351\233\206\346\210\220Locust\345\256\236\347\216\260\346\233\264\345\245\275\347\232\204\346\200\247\350\203\275\346\265\213\350\257\225\344\275\223\351\252\214.md" @@ -118,7 +118,7 @@ class WebPageUser(HttpLocust): 后面的操作就完全是[`Locust`]的内容了,使用方式完全一样。 -![](/images/locust-start.jpg) +![](/image/locust-start.jpg) ## 优化1:自动生成locustfile @@ -319,7 +319,7 @@ $ locusts -f examples/first-testcase.yml --full-speed -P 8088 [2017-08-26 23:51:47,085] bogon/INFO/locust.runners: Client 'bogon_80a804cda36b80fac17b57fd2d5e7cdb' reported as ready. Currently 4 clients ready to swarm. ``` -![](/images/locusts-full-speed.jpg) +![](/image/locusts-full-speed.jpg) 后续,[`ApiTestEngine`]将持续进行优化,欢迎大家多多反馈改进建议。 diff --git "a/content/post/OpenSource/HttpRunner/HttpRunner 2.0 \346\255\243\345\274\217\345\217\221\345\270\203.md" "b/content/post/OpenSource/HttpRunner/HttpRunner 2.0 \346\255\243\345\274\217\345\217\221\345\270\203.md" index 2c70bbf..c385f15 100644 --- "a/content/post/OpenSource/HttpRunner/HttpRunner 2.0 \346\255\243\345\274\217\345\217\221\345\270\203.md" +++ "b/content/post/OpenSource/HttpRunner/HttpRunner 2.0 \346\255\243\345\274\217\345\217\221\345\270\203.md" @@ -101,7 +101,7 @@ tags: 因此,借着 2.0 版本发布之际,我自己用 Keynote 画了一个。 -![HttpRunner-logo](/images/HttpRunner-logo.png) +![HttpRunner-logo](/image/HttpRunner-logo.png) 个人的美工水平实在有限,让大家见笑了。 diff --git "a/content/post/OpenSource/HttpRunner/HttpRunner \345\256\236\347\216\260\345\217\202\346\225\260\345\214\226\346\225\260\346\215\256\351\251\261\345\212\250\346\234\272\345\210\266.md" "b/content/post/OpenSource/HttpRunner/HttpRunner \345\256\236\347\216\260\345\217\202\346\225\260\345\214\226\346\225\260\346\215\256\351\251\261\345\212\250\346\234\272\345\210\266.md" index 4f81dfc..f8ac5bb 100644 --- "a/content/post/OpenSource/HttpRunner/HttpRunner \345\256\236\347\216\260\345\217\202\346\225\260\345\214\226\346\225\260\346\215\256\351\251\261\345\212\250\346\234\272\345\210\266.md" +++ "b/content/post/OpenSource/HttpRunner/HttpRunner \345\256\236\347\216\260\345\217\202\346\225\260\345\214\226\346\225\260\346\215\256\351\251\261\345\212\250\346\234\272\345\210\266.md" @@ -41,7 +41,7 @@ tags: 在 LoadRunner 中,可以在脚本中创建一个参数,然后参数会保存到一个`.dat`的文件中,例如下图中的`psd.dat`。 -![](/images/loadrunner-parameterize.jpg) +![](/image/loadrunner-parameterize.jpg) 在`.dat`文件中,是采用表格的形式来存储参数值,结构与`CSV`基本一致。 @@ -282,7 +282,7 @@ x & y: 听上去很高大上,但实际却异常简单,直接对照着[代码][parameter-data-driven]来说吧。 -![](/images/httprunner-parameterize.jpg) +![](/image/httprunner-parameterize.jpg) 对于每一组参数组合情况来说,我们完全可以将其视为当前用例集运行时定义的变量值。而在 HttpRunner 中每一次运行测试用例集的时候都需要对`runner.Runner`做一次初始化,里面会用到定义的变量(即`config_dict["variables"]`),那么,我们完全可以在每次初始化的时候将组合好的参数作为变量传进去,假如存在同名的变量,就进行覆盖。 diff --git "a/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266.md" "b/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266.md" index fd6914f..a604248 100644 --- "a/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266.md" +++ "b/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266.md" @@ -68,7 +68,7 @@ tags: 按照常规的接口测试用例编写方式,我们需要创建3个场景文件,然后在各个文件中分别描述三个测试场景相关的接口信息。示意图如下所示。 -![](/images/httprunner-testcase-layer-1.jpeg) +![](/image/httprunner-testcase-layer-1.jpeg) 在本例中,接口(`API_1/2/6`)在场景A和场景C中都进行了定义;接口(`API_3/4/5`)在场景A和场景B中都进行了定义;接口(`API_7/8`)在场景B和场景C中都进行了定义。可以预见,当测试场景增多以后,接口定义描述的维护就会变得非常困难和繁琐。 @@ -80,7 +80,7 @@ tags: 示意图如下所示。 -![](/images/httprunner-testcase-layer-2.jpeg) +![](/image/httprunner-testcase-layer-2.jpeg) 具体地,我们可以约定将项目的所有API接口定义放置在 `api` 目录下,并在 `api` 目录中按照项目的系统模块来组织接口的定义;同时,将测试场景放置到 `testcases` 目录中。 @@ -162,7 +162,7 @@ tests 实现接口的分层定义描述后,我们就可以避免接口的重复定义。但是,我们回过头来看之前的案例,发现仍然会存在一定的重复。 -![](/images/httprunner-testcase-layer-3.jpeg) +![](/image/httprunner-testcase-layer-3.jpeg) 如上图所示,场景A和场景C都包含了注册新账号(`API_1/2`)和查看登录状态(`API_6`),场景A和场景B都包含了登录已有账号(`API_3/4/5`),场景B和场景C都包含了注销登录(`API_7/8`)。 @@ -172,7 +172,7 @@ tests 玩过积木的同学可能就会想到,我们也可以将系统的常用功能封装为模块(suite),只需要在模块中定义一次,然后就可以在测试场景中重复进行引用,从而避免了模块功能的重复描述。 -![](/images/httprunner-testcase-layer-4.jpeg) +![](/image/httprunner-testcase-layer-4.jpeg) 具体地,我们可以约定将项目的所有模块定义放置在 `suite` 目录下,并在 `suite` 目录中按照项目的功能来组织模块的定义。 diff --git "a/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266\357\274\210\351\200\202\347\224\250\344\272\216 2.X\357\274\211.md" "b/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266\357\274\210\351\200\202\347\224\250\344\272\216 2.X\357\274\211.md" index 4d3a13b..b6aa7ad 100644 --- "a/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266\357\274\210\351\200\202\347\224\250\344\272\216 2.X\357\274\211.md" +++ "b/content/post/OpenSource/HttpRunner/HttpRunner \347\232\204\346\265\213\350\257\225\347\224\250\344\276\213\345\210\206\345\261\202\346\234\272\345\210\266\357\274\210\351\200\202\347\224\250\344\272\216 2.X\357\274\211.md" @@ -22,7 +22,7 @@ tags: 逻辑关系图如下所示: -![](/images/20190418145309.png) +![](/image/20190418145309.png) 同时,强调如下几点核心概念: diff --git "a/content/post/OpenSource/HttpRunner/HttpRunner \351\200\232\350\277\207 skip \346\234\272\345\210\266\345\256\236\347\216\260\345\257\271\346\265\213\350\257\225\347\224\250\344\276\213\347\232\204\345\210\206\347\273\204\346\211\247\350\241\214\346\216\247\345\210\266.md" "b/content/post/OpenSource/HttpRunner/HttpRunner \351\200\232\350\277\207 skip \346\234\272\345\210\266\345\256\236\347\216\260\345\257\271\346\265\213\350\257\225\347\224\250\344\276\213\347\232\204\345\210\206\347\273\204\346\211\247\350\241\214\346\216\247\345\210\266.md" index 80e50ca..6b926cd 100644 --- "a/content/post/OpenSource/HttpRunner/HttpRunner \351\200\232\350\277\207 skip \346\234\272\345\210\266\345\256\236\347\216\260\345\257\271\346\265\213\350\257\225\347\224\250\344\276\213\347\232\204\345\210\206\347\273\204\346\211\247\350\241\214\346\216\247\345\210\266.md" +++ "b/content/post/OpenSource/HttpRunner/HttpRunner \351\200\232\350\277\207 skip \346\234\272\345\210\266\345\256\236\347\216\260\345\257\271\346\265\213\350\257\225\347\224\250\344\276\213\347\232\204\345\210\206\347\273\204\346\211\247\350\241\214\346\216\247\345\210\266.md" @@ -187,7 +187,7 @@ def _run_test(self, testcase_dict): 在运行该测试集后,生成的测试报告如下所示。 -![](/images/httprunner-skip.jpg) +![](/image/httprunner-skip.jpg) diff --git "a/content/post/OpenSource/HttpRunner/\347\272\246\345\256\232\345\244\247\344\272\216\351\205\215\347\275\256\357\274\232ApiTestEngine\345\256\236\347\216\260\347\203\255\345\212\240\350\275\275\346\234\272\345\210\266.md" "b/content/post/OpenSource/HttpRunner/\347\272\246\345\256\232\345\244\247\344\272\216\351\205\215\347\275\256\357\274\232ApiTestEngine\345\256\236\347\216\260\347\203\255\345\212\240\350\275\275\346\234\272\345\210\266.md" index b604f73..aed6f3a 100644 --- "a/content/post/OpenSource/HttpRunner/\347\272\246\345\256\232\345\244\247\344\272\216\351\205\215\347\275\256\357\274\232ApiTestEngine\345\256\236\347\216\260\347\203\255\345\212\240\350\275\275\346\234\272\345\210\266.md" +++ "b/content/post/OpenSource/HttpRunner/\347\272\246\345\256\232\345\244\247\344\272\216\351\205\215\347\275\256\357\274\232ApiTestEngine\345\256\236\347\216\260\347\203\255\345\212\240\350\275\275\346\234\272\345\210\266.md" @@ -83,7 +83,7 @@ tags: 将这两点与测试用例引擎的实现机制结合起来,`ApiTestEngine`在运行过程中的热加载机制应该就如下图所示。 -![](/images/ate-hot-plugin.png) +![](/image/ate-hot-plugin.png) 这个流程图对热加载机制描述得已经足够清晰了,我再针对其中的几个点进行说明: diff --git "a/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\344\275\277\347\224\250Python\345\256\236\347\216\260UI\350\207\252\345\212\250\345\214\226.md" "b/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\344\275\277\347\224\250Python\345\256\236\347\216\260UI\350\207\252\345\212\250\345\214\226.md" index d3fd885..cfdde30 100644 --- "a/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\344\275\277\347\224\250Python\345\256\236\347\216\260UI\350\207\252\345\212\250\345\214\226.md" +++ "b/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\344\275\277\347\224\250Python\345\256\236\347\216\260UI\350\207\252\345\212\250\345\214\226.md" @@ -154,7 +154,7 @@ button = d(className='android.widget.Button', text='Next') Google官方提供了两个工具,`hierarchyviewer`和`uiautomatorviewer`,这两个工具都位于`/tools/`目录下。关于这两个工具的区别及其各自的特点,本文不进行详细介绍,我们当前只需要知道,在查看控件属性方面,这两个工具实现的功能完全相同,界面也完全相同,我们任选其一即可。 {: .center} -![uiautomatorviewer](/images/uiautomatorviewer.png) +![uiautomatorviewer](/image/uiautomatorviewer.png) 通过这个工具,我们可以查看到当前设备屏幕中的UI元素信息: diff --git "a/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\345\220\257\345\212\250\346\265\201\351\207\217\357\274\2102\357\274\211.md" "b/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\345\220\257\345\212\250\346\265\201\351\207\217\357\274\2102\357\274\211.md" index 21d5666..8c91a8d 100644 --- "a/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\345\220\257\345\212\250\346\265\201\351\207\217\357\274\2102\357\274\211.md" +++ "b/content/post/Testing/Android/Android App\346\214\201\347\273\255\351\233\206\346\210\220\346\200\247\350\203\275\346\265\213\350\257\225\357\274\232\345\220\257\345\212\250\346\265\201\351\207\217\357\274\2102\357\274\211.md" @@ -61,7 +61,7 @@ tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 2621 好在`wireshark`有非常强大的筛选功能。对于本案例,我们可以先确定出美国服务器的host或IP,例如host为`ucus.ucweb.com`,那么我们就可以在筛选器中通过`http.host == "ucus.ucweb.com"`语句,即可筛选出所有本地与美国服务器的通讯交互数据。 -![wireshark host filter](/images/wireshark_host_filter.png) +![wireshark host filter](/image/wireshark_host_filter.png) 对于更丰富的筛选功能,大家可以根据实际需求查询`wireshark`的帮助文档,在此就不再进行展开。 @@ -69,11 +69,11 @@ tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 2621 首先,找出该次请求的`TCP Stream`。 -![wireshark tcp stream menu](/images/wireshark_tcp_stream_menu.png) +![wireshark tcp stream menu](/image/wireshark_tcp_stream_menu.png) 在筛选出的`TCP Stream`中,将各条记录的Length进行求和,即可得到总的大小。 -![wireshark tcp stream data](/images/wireshark_tcp_stream_data.png) +![wireshark tcp stream data](/image/wireshark_tcp_stream_data.png) 例如,发送流量的总和,即`100.84.126.160`->`168.235.199.134`的总和,加和总值为3722bytes;接收流量的总和,即`168.235.199.134`->`100.84.126.160`的总和,加和总值为6300bytes。 @@ -81,11 +81,11 @@ tcpdump: listening on any, link-type LINUX_SLL (Linux cooked), capture size 2621 【Statistics】->【Endpoints】 -![wireshark endpoints menu](/images/wireshark_endpoints_menu.png) +![wireshark endpoints menu](/image/wireshark_endpoints_menu.png) 在Endpoints界面中,选择`TCP` tab,勾选“Limit to display filter”,即可看到通讯流量汇总数据。 -![wireshark tcp stream data](/images/wireshark_tcp_stream_data.png) +![wireshark tcp stream data](/image/wireshark_tcp_stream_data.png) 可以看出,这个的汇总数值与前面计算得到的数值完全相同。 diff --git "a/content/post/Testing/WebService/\345\237\272\344\272\216HTTP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" "b/content/post/Testing/WebService/\345\237\272\344\272\216HTTP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" index f0baaca..a9f8c15 100755 --- "a/content/post/Testing/WebService/\345\237\272\344\272\216HTTP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" +++ "b/content/post/Testing/WebService/\345\237\272\344\272\216HTTP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" @@ -23,13 +23,13 @@ http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx)的基础上 例如,接口getWeatherbyCityName的测试工具如下图所示。在theCityName参数框内输入城市的名称,点击【调用】按钮,即可实现对getWeatherbyCityName接口的调用,并获得返回结果。 -![](/images/150213_01.png) +![](/image/150213_01.png) 在WebService的调用过程中,我们无需关注它具体是采用什么样的通讯协议,因为不管是何种通讯协议,具体传输实现还是会依赖于HTTP。因此,我们可以通过HTTP抓包工具对WebService调用过程中的通讯交互数据包进行捕捉。 在这里我们采用Fiddler Web Debugger进行演示。在浏览器中调用接口getWeatherbyCityName的测试工具时,在Fiddler中抓取到对应的HTTP请求,如下图所示。 -![](/images/150213_02.png) +![](/image/150213_02.png) 从该HTTP请求可以获得如下关键信息: @@ -43,11 +43,11 @@ http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx)的基础上 在Fiddler中,可使用Composer对HTTP请求进行构造,如下图所示。 -![](/images/150213_03.png) +![](/image/150213_03.png) 在Request Body中,修改请求参数theCityName为不同的城市(例如,重庆),Execute请求,查看返回结果。 -![](/images/150213_04.png) +![](/image/150213_04.png) ## 在LoadRunner中构造HTTP请求 @@ -57,7 +57,7 @@ http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx)的基础上 具体的代码实现及回放结果如下图所示。 -![](/images/150213_05.png) +![](/image/150213_05.png) 虽然在LoadRunner中返回的中文显示为乱码,但是从城市编码(57516)可以看出,脚本执行后返回了正确的结果。 diff --git "a/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216SOAP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" "b/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216SOAP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" index 882fe93..df65967 100755 --- "a/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216SOAP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" +++ "b/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216SOAP\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" @@ -74,11 +74,11 @@ SOAPAction: "http://WebXml.com.cn/getWeatherbyCityName" 在LoadRunner的Web Services协议中,点击【Import SOAP】,加载之前准备好的SOAP报文,即xml文件;加载完成后,在URL和SOAP Action中分别填入获取得到的地址信息;在Response Parameter中填写存储返回内容的参数名称;如下图所示。 -![](/images/130806_01.png) +![](/image/130806_01.png) 点击【OK】后,便能在脚本界面中生成一个soap_request函数,如下图所示。 -![](/images/130806_02.png) +![](/image/130806_02.png) 通过上图可知,SOAP报文中的全部内容已成功转换为LoadRunner的soap_request函数。 @@ -86,7 +86,7 @@ SOAPAction: "http://WebXml.com.cn/getWeatherbyCityName" 将脚本中的字段theCityName赋值为“广州”;在“Run-time Settings”中打开日志“Extended log”,勾选“Parameter substitution”和“Data returned by server”。运行脚本后,查看“Replay Log”,如下图所示。 -![](/images/130806_03.png) +![](/image/130806_03.png) 在这里如果将脚本回放得到的结果与在浏览器中调用返回的结果进行对比,会发现内容并不一致。在LoadRunner脚本中将theCityName更改为“深圳”、“上海”等城市后重新回放脚本,会发现内容仍然不一致,且LoadRunner每次回放得到的结果都相同。 @@ -94,7 +94,7 @@ SOAPAction: "http://WebXml.com.cn/getWeatherbyCityName" 对LR脚本中需传送的汉字进行编码转换,即将脚本中的汉字转换为UTF-8,转换方法如下图所示: -![](/images/130806_04.png) +![](/image/130806_04.png) 重新回放脚本,查看Replay Log。再次对比LoadRunner的Replay Log和浏览器的返回页面可知,LoadRunner对Web Service实现了正确的调用。 diff --git "a/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216WSDL\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" "b/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216WSDL\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" index ab8d71b..ada33e5 100755 --- "a/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216WSDL\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" +++ "b/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/LoadRunner/LoadRunner\345\237\272\344\272\216WSDL\347\232\204WebService\346\265\213\350\257\225\346\226\271\346\263\225.md" @@ -27,7 +27,7 @@ http://webservice.webxml.com.cn/WebServices/WeatherWebService.asmx)。 采用Loadrunner测试WebService时,在单协议里面选择Web Services即可。当然,这并不意味着Loadrunner测试WebService只能采用Web Services协议,在后续的文章中将向大家介绍如何通过HTTP协议来测试WebService。 -![](/images/130802_01.png) +![](/image/130802_01.png) ## 导入WebService的描述信息WSDL @@ -44,17 +44,17 @@ WSDL 是基于 XML 的用于描述 WebService 以及如何访问 WebService 的 通过WSDL的URL地址进行导入时,操作方式如下图所示。 -![](/images/130802_02.png) +![](/image/130802_02.png) 需要说明的是,填写的URL地址末尾必须包含`?WSDL`。换句话说,只有在以`?WSDL`结尾时才能对应到WSDL文件的路径。大家可以在浏览器中对WSDL的URL地址进行访问,查看WSDL当前是否有效。 如果选择直接导入本地WSDL文件的方式,则需要先将WebService对应的WSDL文件下载至本地。下载时,只需将WebService的地址末尾加上 "?WSDL" 后在浏览器中进行访问,然后对网页进行保存时将文件另存为".wsdl"的文件即可。如下图所示。 -![](/images/130802_03.png) +![](/image/130802_03.png) 获取到WSDL文件以后,便可在LoadRunner中以文件的进行导入,操作方式如下图所示。 -![](/images/130802_04.png) +![](/image/130802_04.png) 两种导入方式效果都是一样的,采用任意一种方式都能将WebService的描述信息导入至LoadRunner供其调用。 @@ -62,7 +62,7 @@ WSDL 是基于 XML 的用于描述 WebService 以及如何访问 WebService 的 - 采用**Import URL**的方式可以方便本地获取到最新的WebService描述,当远程服务器端的WebService发生变动以后,本地端可直接对WSDL进行更新,而不需对WSDL进行重新导入。在LoadRunner中,甚至可以通过设置使LoadRunner每次打开脚本的时候自动更新WSDL,如下图所示。 -![](/images/130802_05.png) +![](/image/130802_05.png) - 采用**Import File**方式的优点在于,可以对下载到本地的WSDL文件进行手工编辑后再使用;而缺点则是无法获取到最新的WebService的描述信息,若要更新则需重新下载WSDL文件并重新导入。 @@ -72,11 +72,11 @@ WSDL 是基于 XML 的用于描述 WebService 以及如何访问 WebService 的 在成功导入WSDL以后,在【Operation】栏目下即可看到所有可供调用的接口。值得注意的是,在本测试案例中,每个接口均包含2个`Port Name`,这是因为该WebService为每个服务接口提供了SOAP1.1和SOAP1.2两个版本的SOAP调用方式。 -![](/images/130802_06.png) +![](/image/130802_06.png) 对比下图可知,这和网页上展示的接口是一致的。 -![](/images/130802_07.png) +![](/image/130802_07.png) ## 创建调用函数web_service_call @@ -88,7 +88,7 @@ LoadRunner提供的调用函数为web_service_call。调用该函数时,可以 点击【Add Service Call】后进入Web Service Call的可视化编辑界面,如下图所示。 -![](/images/130802_08.png) +![](/image/130802_08.png) 在【Add Service Call】的可视化界面中,对所需调用的Service、Port Name和Operation进行选择。在Operation列表中,可以看到存在5个可供调用的方法,对于每一个Operation,在Port Name下拉框中均可以选择WeatherWebServiceSoap和WeatherWebServiceSoap12,这和上一步骤在【Operations】中查看到的完全一致。 @@ -98,22 +98,22 @@ LoadRunner提供的调用函数为web_service_call。调用该函数时,可以 因此,使用getWeatherbyCityName函数接口时我们需对其传入参数theCityName。具体操作时,选中Input Arguments中的参数名theCityName,勾选其右侧的“Include argument in call”,在Value中输入城市名称即可,此处我们输入的是“广州”,如下图所示。 -![](/images/130802_09.png) +![](/image/130802_09.png) 若需要调用getWeatherbyCityName函数的返回结果,则需要事先将其返回结果保存至参数里面。具体操作时,选中Output Arguments中的参数名getWeatherbyCityNameResult[1],勾选其右侧的“Save returned value in parameter”,在Parameter中输入参数名即可。如下图所示。 -![](/images/130802_10.png) +![](/image/130802_10.png) 完成对Input Arguments和Output Arguments的设置后,点击【OK】按钮,便可看见脚本中新增了一个web_service_call函数,如下图所示。 -![](/images/130802_11.png) +![](/image/130802_11.png) 通过上图可知,之前我们在可视化界面的所有设置均已转换至web_service_call函数。 ## 回放脚本,查看结果 在“Run-time Settings”中打开日志“Extended log”,勾选“Parameter substitution”和“Data returned by server”。运行脚本后,查看“Replay Log”,如下图所示。 -![](/images/130802_12.png) +![](/image/130802_12.png) 详细结果如下所示。 @@ -123,7 +123,7 @@ theWeatherInfo = 在浏览器访问该WebService,查询“广州”时得到结果如下图所示。 -![](/images/130802_13.png) +![](/image/130802_13.png) 通过对比LoadRunner的Replay Log和浏览器的返回页面可知,LoadRunner对Web Service进行了正确的调用。 @@ -131,20 +131,20 @@ theWeatherInfo = 脚本虽已调试成功,可以得到正确的结果。但若要进行性能测试,我们还需对脚本进行参数化,如下图所示。 -![](/images/130802_14.png) +![](/image/130802_14.png) 或者,如果我们是只想利用返回报文的一小部分,而不是全部。在这种情况下,我们可以指定将某部分保存至参数,以便后续的使用。 例如,我们只想获得某个城市当天的最低温度和最高温度。通过返回报文可知,该字段是输出结果中的第6个字段。那么,我们便可以将该字段保存至一个参数,这里指定为Lowest_Highest_Temperature,如下图所示。 -![](/images/130802_15.png) +![](/image/130802_15.png) 生成脚本如下所示: -![](/images/130802_16.png) +![](/image/130802_16.png) 运行结果如下图所示。 -![](/images/130802_17.png) +![](/image/130802_17.png) 当然,此处只是列举了一个简单的例子。通过对web_service_call函数的灵活应用,可以实现更多复杂、强大的功能。 diff --git "a/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/Locust/\346\267\261\345\205\245\346\265\205\345\207\272\345\274\200\346\272\220\346\200\247\350\203\275\346\265\213\350\257\225\345\267\245\345\205\267Locust\357\274\210\344\275\277\347\224\250\347\257\207\357\274\211.md" "b/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/Locust/\346\267\261\345\205\245\346\265\205\345\207\272\345\274\200\346\272\220\346\200\247\350\203\275\346\265\213\350\257\225\345\267\245\345\205\267Locust\357\274\210\344\275\277\347\224\250\347\257\207\357\274\211.md" index af32f9f..7d46d9e 100644 --- "a/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/Locust/\346\267\261\345\205\245\346\265\205\345\207\272\345\274\200\346\272\220\346\200\247\350\203\275\346\265\213\350\257\225\345\267\245\345\205\267Locust\357\274\210\344\275\277\347\224\250\347\257\207\357\274\211.md" +++ "b/content/post/Testing/\346\200\247\350\203\275\346\265\213\350\257\225/Locust/\346\267\261\345\205\245\346\265\205\345\207\272\345\274\200\346\272\220\346\200\247\350\203\275\346\265\213\350\257\225\345\267\245\345\205\267Locust\357\274\210\344\275\277\347\224\250\347\257\207\357\274\211.md" @@ -19,7 +19,7 @@ tags: 先从`Locust`的名字说起。`Locust`的原意是蝗虫,原作者之所以选择这个名字,估计也是听过这么一句俗语,“蝗虫过境,寸草不生”。我在网上找了张图片,大家可以感受下。 -![](/images/14875962785342.jpg) +![](/image/14875962785342.jpg) 而`Locust`工具生成的并发请求就跟一大群蝗虫一般,对我们的被测系统发起攻击,以此检测系统在高并发压力下是否能正常运转。 @@ -361,17 +361,17 @@ $ locust -H https://debugtalk.com -f demo.py --slave --master-host=