当前位置: 首页 > news >正文

婚纱影楼网站建设手机网站生成小程序

婚纱影楼网站建设,手机网站生成小程序,永久短链接,莱芜新闻直播目录 背景 框架 ginkgo初始化 抓包运行脚本 目录说明 ∮./business ∮./conf ∮./utils ∮./testcase testcase 用例目录结构规则 示例 实现思路 解析Har数据 定义结构体 解析到json 转换请求数据 转换请求 转换请求参数 写业务请求数据 写gotest测试…目录 背景 框架 ginkgo初始化 抓包运行脚本 目录说明 ∮./business ∮./conf ∮./utils ∮./testcase testcase 用例目录结构规则 ¶示例 实现思路 解析Har数据 定义结构体 解析到json 转换请求数据 转换请求 转换请求参数 写业务请求数据 写gotest测试用例数据 初始化写入suit文件 格式化测试文件 install生成的业务请求目录 格式化响应断言 可能遇到的问题 完整代码 详细代码如下注释已经给得比较清晰 资料获取方法 背景 之前写过一篇博客介绍怎么用Python通过解析抓包数据完成自动化用例的编写。最近这段时间在使用go test所以就在想能不能也使用代码来生成自动化用例快速提升测试用例覆盖率。说干就干。 框架 首先介绍一下我们使用的测框架 项信息安装备注GO版本go1.12.9 darwin/amd64略测试框架ginkgogo get -u github.com/onsi/ginkgo/ginkgo断言库testify/assertgo get github.com/stretchr/testify官方配套的断言库是gomega ginkgo初始化 初始化: cd path/to/package/you/want/to/test ginkgo bootstrap创建示例用例ginkgo generate (需要手动添加测试用例)运行测试 go testor ginkgo 注-v加上参数可打印运行信息 抓包运行脚本 使用抓包工具如Charles抓包把数据包导出为har格式保存在当前目录下 如何安装抓包工具在本文就不赘述了抓包过滤出想要的数据导出保存的格式注意选择为har 根据实际情况修改全局变量信息如bizBaseFolder、serverName、userFile等使用go run gentest.go运行脚本即可 目录说明 然后我们一起来了解一下我们的目录结构定义。 ∮./business 业务封装封装具体的请求及测试数据 ∮./conf 配置信息及接口请求参数初始化封装 ∮./utils 公共函数封装 ∮./testcase 接口测试用例目录 testcase 用例目录结构规则 基本原则 根据项目、模块、接口功能逐级区分建议最多3层目录层级 ¶示例 软件测试论坛项目组/论坛项目/帖子模块/创建帖子接口 CN_TestBBS/bbs/post/post_test.go基础账号项目/首页项目/白名单接口 CN_account/homepage/whitelist_test.go 实现思路 按照har文件的JSON结构定义对应的结构体然后解析数据生成请求数据生成断言数据初始化测试套suite格式化代码初始化包引用信息。 解析Har数据 定义结构体 Log struct {version stringcreator stringEntries []struct {startedDateTime stringtime stringRequest struct {...解析到json func UnpackHar(har []byte) (logs *Har) {err : json.Unmarshal(har, logs)if err ! nil {fmt.Println(err)}return }转换请求数据 转换请求 转换请求参数 GET // 格式化请求参数为标准请求string getReqParam : make(map[string]interface{}, 1) if len(v.Request.QueryString) 0 {for _, query : range v.Request.QueryString {getReqParam[query.Name] query.Value} } // 获取postReq数据 postReqParamStr : v.Request.PostData.Textif v.Request.Method GET {paramstr genGetParam(InterfaceName, getReqParam) }func genGetParam(interfaceName string, param map[string]interface{}) (formatParam string) {// 对于请求参数的value值为 数组if len(param) 0 {for k, v : range param {switch vv : v.(type) {case []interface{}:fmt.Sprintf(k, is an array:, vv)temp, _ : json.Marshal(param)formatParam fmt.Sprintf(%sParam %s, interfaceName, fmt.Sprintf(%v, string(temp)))returndefault:// fmt.Println(k, is of a type didnt handle)}}}temp, _ : json.Marshal(param)formatParam fmt.Sprintf(%sParam map[string]interface{} %s, interfaceName, fmt.Sprintf(%v, string(temp)))return }POST postReqParamStr : v.Request.PostData.Textif v.Request.Method POST {paramstr genPostParam(InterfaceName, postReqParamStr) } func genPostParam(interfaceName string, postReqParamStr string) (formatParam string) {// formatParam fmt.Sprintf(%sParam map[string]interface{} %s, interfaceName, param)// fmt.Sprintf(%v, string(temp))postReqParam : make(map[string]interface{}, 1)if len(postReqParamStr) 0 {// 判断第一个字符是否为{}, 做传递数据为数组[]的兼容if []rune(postReqParamStr)[0] { {var x interface{}err : json.Unmarshal([]byte(postReqParamStr), x)if err ! nil {fmt.Println(err, err)}postReqParam x.(map[string]interface{})// fmt.Println(postReqParam)// 判断value中是否存在数组for k, v : range postReqParam {switch vv : v.(type) {// switch vv : v.(type) {case []interface{}:fmt.Sprintf(k, is an array:, vv)// param[k] fmt.Sprintf(%s, vv)temp, _ : json.Marshal(postReqParam)formatParam fmt.Sprintf(%sParam %s, interfaceName, fmt.Sprintf(%v, string(temp)))paramType stringreturndefault:formatParam genGetParam(interfaceName, postReqParam)// fmt.Println(k, is of a type didnt handle)}}// 如果为数组做如下处理} else {var y []interface{}err : json.Unmarshal([]byte(postReqParamStr), y)if err ! nil {fmt.Println(err, err)}postReqParam y[0].(map[string]interface{})temp, _ : json.Marshal(postReqParam)// 声明请求类型paramType []map[string]interface{}formatParam fmt.Sprintf(%sParam []map[string]interface{}{%s}, interfaceName, string(temp))// 无法使用 判断类型 Param : utils.MapDeepCopy(Hebinz123.XlppcPlaylistApiV1RemarkDelParam)}}// temp, _ : json.Marshal(param)// formatParam fmt.Sprintf(%sParam map[string]interface{} %s, interfaceName, fmt.Sprintf(%v, string(temp)))return } 写业务请求数据 写gotest测试用例数据 格式化请求参数为标准请求string。 初始化写入suit文件 这里有一个注意点Test后紧接的数据必须是大写。 格式化测试文件 使用goimports库初始化导入数据包。 install生成的业务请求目录 使用go install目录生成导入业务请求目录 格式化响应断言 使用类型判断格式化接口返回数据为标准断言string。 可能遇到的问题 初始化读取文件的存储buf的size和其实际大小不一致时json 解析出错“invalid character \x00 after top-level value”go install 执行失败导致测试用例无法找到其依赖包get请求post请求参数在har文件中的存储方式不一致获取数据的方式差别很大域名及接口命名规则不一致-、.等等风格不一致测试suite 紧接Test后方的字符需为大写的字母否则服务无法被发现所以需要做大小写转换 完整代码 详细代码如下注释已经给得比较清晰 package mainimport (encoding/base64encoding/jsonfmtosos/execpath/filepathstrings )var (baseDomain test.bbs.com // 测试域名用于切割出请求路径bizBaseFolder business/CN_bbs //业务请求目录testCaseBaseFolder testcase/CN_bbs // 测试用例目录serverName cinecismGo // 服务名paramType )func main() {userFile : 20190917-cinecismgo.har // 抓包文件地址fl, err : os.Open(userFile)if err ! nil {fmt.Println(userFile, err)return}defer fl.Close()// 读取har数据fileInfo, err : fl.Stat()buf : make([]byte, fileInfo.Size()) // “invalid character \x00 after top-level value”fl.Read(buf)data : UnpackHar(buf)for _, v : range data.Log.Entries {// 每一个循环初始化请求参数类型paramType map[string]interface{}paramstr : // 初始化 请求path生成标准请求接口名称pathStr, path : initPath(v.Request.URL)InterfaceName : formatInterfaceName(pathStr)// 格式化请求参数为标准请求stringgetReqParam : make(map[string]interface{}, 1)if len(v.Request.QueryString) 0 {for _, query : range v.Request.QueryString {getReqParam[query.Name] query.Value}}// 获取postReq数据postReqParamStr : v.Request.PostData.Textif v.Request.Method GET {paramstr genGetParam(InterfaceName, getReqParam)}if v.Request.Method POST {paramstr genPostParam(InterfaceName, postReqParamStr)}// 格式化接口返回数据为标准断言stringtext, _ : base64.StdEncoding.DecodeString(v.Response.Content.Text)responseAssertStr : initAssert(text)// 创建业务请求文件、测试用例文件run(serverName, path, InterfaceName, v.Request.Method, responseAssertStr, paramstr)// 【待补充】handle Headers数据// fmt.Println(initHeaders(data))} }func initAssert(text []byte) (responseAssertStr string) {if len(text) 0 {var Response interface{}err : json.Unmarshal(text, Response)if err ! nil {fmt.Println(err, err)}responseMap : Response.(map[string]interface{})res : []string{}for k, v : range responseMap {switch vv : v.(type) {case string:// fmt.Println(k, is string, vv)res append(res, fmt.Sprintf(%s, _ : js.Get(\%s\).String() \n assert.Equal(%s, %v), k, k, k, string(vv)))case int64:// fmt.Println(k, is int, vv)res append(res, fmt.Sprintf(%s, _ : js.Get(\%s\).Int() \n assert.Equal(%s, %v), k, k, k, string(vv)))case float64:// fmt.Println(k, is float64, vv)res append(res, fmt.Sprintf(%s, _ : js.Get(\%s\).Int() \n assert.Equal(%s, %v), k, k, k, vv))case bool:// fmt.Println(k, is bool, vv)res append(res, fmt.Sprintf(%s, _ : js.Get(\%s\).Bool() \n assert.Equal(%s, %v), k, k, k, vv))case []interface{}:// fmt.Println(k, is an array:, vv)res append(res, fmt.Sprintf(// Key【%s】的子层级的value值未生成断言系多层级数组数据具体值如下, k))res append(res, fmt.Sprintf(// %v , vv))case map[string]interface{}:// fmt.Println(k, is an map:, vv)temp, _ : json.Marshal(vv)res append(res, fmt.Sprintf(// Key【%s】的子层级value值未生成断言系多层级Map数据具体值如下, k))res append(res, fmt.Sprintf(// %v , string(temp)))default:// fmt.Println(k, is of a type didnt handle, vv)}responseAssertStr strings.Join(res, \n)}}return }func initPath(URL string) (pathStr, path string) {pathStr strings.Split(URL, baseDomain)[1]if strings.Contains(pathStr, ?) {pathStr strings.Split(pathStr, ?)[0]path strings.Split(pathStr, ?)[0]} else {path pathStr}if strings.Contains(pathStr, .) {pathStr strings.Replace(pathStr, ., /, 10)pathStr strings.Replace(pathStr, -, /, 10)}// fmt.Println(path)// fmt.Println(pathStr, pathStr)return }func run(serverName, path, InterfaceName, method, responseAssertStr string, Param string) {// 初始化测试文件InterfaceFilepath : filepath.Join(bizBaseFolder, serverName)Testcasefilepath : filepath.Join(testCaseBaseFolder, serverName)InterfaceFileame : InterfaceName .goTestcasefilename : InterfaceName _test.go// 创建并写入标准请求信息file, err : createFile(InterfaceFilepath, InterfaceFileame)if err ! nil {fmt.Println(createInterfaceFile, err)}writeParam(file, serverName, []string{Param})writeReq(file, InterfaceName, path, method)defer file.Close()// 创建并写入测试用例信息file1, err : createFile(Testcasefilepath, Testcasefilename)if err ! nil {fmt.Println(createTestcasefile, err)}// 写入suit文件initTestsuit(serverName)// 写入测试用例writeTestcase(file1, serverName, InterfaceName, responseAssertStr)defer file1.Close()// 格式化测试文件exec.Command(goimports, -w, InterfaceFilepath).Run()exec.Command(goimports, -w, Testcasefilepath).Run()// 导入InterfaceFilepathexec.Command(go, install, InterfaceFilepath).Run() }func initHeaders(har *Har) map[string]string {var headers make(map[string]string)// fmt.Println(len(har.Log.Entries[0].Request.Headers))for _, v : range har.Log.Entries[0].Request.Headers {headers[v.Name] v.Value}return headers }func createFile(filepaths, filename string) (file *os.File, err error) {os.MkdirAll(filepaths, 0777)file, err os.Create(filepath.Join(filepaths, filename))return }func createInterfaceFile(path, filename string) (file *os.File, err error) {filename filename .gofilepath : bizBaseFolder / path /os.MkdirAll(filepath, 0777)file, err os.Create(filepath filename)return }func createTestcasefile(path, filename string) (file *os.File, err error) {filename filename _test.gofilepath : testCaseBaseFolder / path /os.MkdirAll(filepath, 0777)file, err os.Create(filepath filename)return }func initTestsuit(serverName string) {filename : serverName _suite_test.gofilepath : testCaseBaseFolder / serverName /os.MkdirAll(filepath, 0777)file, err : os.Create(filepath filename)if err ! nil {fmt.Println(initTestsuit Error, err)}// Testsuite后的 首字母需大写否则suite无法正常检索到testcasefile.WriteString(fmt.Sprintf(package %s_testimport (testing. github.com/onsi/ginkgo. github.com/onsi/gomega)func Test%s(t *testing.T) {RegisterFailHandler(Fail)RunSpecs(t, %s Suite)}, serverName, Capitalize(serverName), serverName)) }func writeTestcase(file *os.File, serverName, InterfaceName, responseAssertStr string) {// 接口引入路径 【服务名称.接口名称】interfaceImportPath : serverName . InterfaceName// 接口标准请求参数 【接口名称Param】paramImportPath : interfaceImportPath Param// 接口标准请求参数拷贝请求参数为非标准【map[string]interface{}】类型时该参数为空tempParamStr : // 是否使用mapDeepCopy请求参数为非标准【map[string]interface{}】类型时 使用mapDeepCopy : if paramType ! map[string]interface{} {tempParamStr paramImportPath}if paramType map[string]interface{} {tempParamStr ParammapDeepCopy fmt.Sprintf(Param : utils.MapDeepCopy(%s), paramImportPath)}// fmt.Println(----------------, paramType)file.WriteString(fmt.Sprintf(package %s_test\n\n, serverName))file.WriteString(import . github.com/onsi/ginkgo)file.WriteString(\n\n)file.WriteString(fmt.Sprintf(var _ Describe(%s, func() {headers : common.EntireHeaderParamassert : assert.New(GinkgoT())BeforeEach(func() {By(begin test)})JustBeforeEach(func() {By(just say start)})AfterEach(func() {By(end test)})Context(%s, func() {It(正常%s, func() {%sret, resp, _ : %s(%s, headers)assert.Equal(ret.StatusCode, 200)js, errs : simplejson.NewJson(resp)if errs ! nil {panic(errs)}%s})})}), serverName, InterfaceName, InterfaceName, mapDeepCopy, interfaceImportPath, tempParamStr, responseAssertStr)) }func writeParam(file *os.File, serverName string, params []string) {file.WriteString(fmt.Sprintf(package %s, serverName))file.WriteString(\n\n\n)file.WriteString(var ()for _, param : range params {file.WriteString(param)}file.WriteString())file.WriteString(\n\n\n) }func writeReq(file *os.File, InterfaceName, path, method string) {file.WriteString(fmt.Sprintf(func %s(param %s, header map[string]string) (ret gorequest.Response, content []byte, result string) {path : %surl : CN_bbs.TESTSERVERDOMAIN pathret, content common.Common%s(url, param, header)fmt.Println(ret.Request.URL)// js, _ : simplejson.NewJson([]byte(content))//result, _ js.Get(result).String()return}, InterfaceName, paramType, path, method)) }func genGetParam(interfaceName string, param map[string]interface{}) (formatParam string) {// 对于请求参数的value值为 数组if len(param) 0 {for k, v : range param {switch vv : v.(type) {case []interface{}:fmt.Sprintf(k, is an array:, vv)temp, _ : json.Marshal(param)// 如果是数组格式直接当作字符串处理map[]interface{}格式无法表示该类型参数formatParam fmt.Sprintf(%sParam %s, interfaceName, fmt.Sprintf(%v, string(temp)))returndefault:// fmt.Println(k, is of a type didnt handle)}}}temp, _ : json.Marshal(param)formatParam fmt.Sprintf(%sParam map[string]interface{} %s, interfaceName, fmt.Sprintf(%v, string(temp)))return }func genPostParam(interfaceName string, postReqParamStr string) (formatParam string) {// formatParam fmt.Sprintf(%sParam map[string]interface{} %s, interfaceName, param)// fmt.Sprintf(%v, string(temp))postReqParam : make(map[string]interface{}, 1)if len(postReqParamStr) 0 {// 判断第一个字符是否为{}, 做传递数据为数组[]的兼容if []rune(postReqParamStr)[0] { {var x interface{}err : json.Unmarshal([]byte(postReqParamStr), x)if err ! nil {fmt.Println(err, err)}postReqParam x.(map[string]interface{})// fmt.Println(postReqParam)// 判断value中是否存在数组for k, v : range postReqParam {switch vv : v.(type) {// switch vv : v.(type) {case []interface{}:fmt.Sprintf(k, is an array:, vv)// param[k] fmt.Sprintf(%s, vv)temp, _ : json.Marshal(postReqParam)formatParam fmt.Sprintf(%sParam %s, interfaceName, fmt.Sprintf(%v, string(temp)))paramType stringreturndefault:formatParam genGetParam(interfaceName, postReqParam)// fmt.Println(k, is of a type didnt handle)}}// 如果为数组做如下处理} else {var y []interface{}err : json.Unmarshal([]byte(postReqParamStr), y)if err ! nil {fmt.Println(err, err)}postReqParam y[0].(map[string]interface{})temp, _ : json.Marshal(postReqParam)// 声明请求类型paramType []map[string]interface{}formatParam fmt.Sprintf(%sParam []map[string]interface{}{%s}, interfaceName, string(temp))// 无法使用 判断类型 Param : utils.MapDeepCopy(Hebinz123.CNppcPlaylistApiV1RemarkDelParam)}}// temp, _ : json.Marshal(param)// formatParam fmt.Sprintf(%sParam map[string]interface{} %s, interfaceName, fmt.Sprintf(%v, string(temp)))return }func formatInterfaceName(path string) (InterfaceName string) {paths : strings.Split(path, /)for k, v : range paths {paths[k] Capitalize(v)}InterfaceName strings.Join(paths, )return }// Capitalize 字符首字母大写 func Capitalize(str string) string {var upperStr stringvv : []rune(str)for i : 0; i len(vv); i {if i 0 {if vv[i] 97 vv[i] 122 { // 判断是否是小写字母vv[i] - 32 // string的码表相差32位upperStr string(vv[i])} else {fmt.Println(Not begins with lowercase letter,)return str}} else {upperStr string(vv[i])}}return upperStr }// Har Logs 解析 type Har struct {Log struct {version stringcreator stringEntries []struct {startedDateTime stringtime stringRequest struct {Method stringURL stringhttpVersion stringCookies []stringHeaders []struct {Name stringValue string}QueryString []struct {Name stringValue string}PostData struct {MimeType stringText string}headersSize int32bodySize int32}Response struct {_charlesStatus stringStatus int32StatusText stringhttpVersion stringcookies []stringHeaders []struct {Name stringValue string}Content struct {size int32mimeType stringText stringEncoding string}redirectURL stringheadersSize intbodySize int}serverIPAddress stringcache map[string]stringtimings map[string]int32}} }// UnpackHar 解析 har func UnpackHar(har []byte) (logs *Har) {err : json.Unmarshal(har, logs)if err ! nil {fmt.Println(err)}return }文中可能存在描述不正确欢迎大神们指正补充 感谢阅读如果觉得对你有帮助就在右下角点个赞吧感谢 合抱之木生于毫末九层之台起于累土千里之行始于足下。 资料获取方法 【留言777】 各位想获取源码等教程资料的朋友请点赞 评论 收藏三连 三连之后我会在评论区挨个私信发给你们~
http://www.sadfv.cn/news/326169/

相关文章:

  • 百度网站的目标多商户开源商城
  • 用于做分析图 的地图网站百度网站站长工具
  • 传统网站有没有建设必要性如何用手机创建网站
  • 网站建设合同】游戏外包公司是干嘛的
  • 乒乓球网站怎么做网站描述关键词
  • 国内外网站建设2017美瞳网站建设
  • 常见的建站工具桐乡建设局网站
  • 邮箱官方网站注册腾讯云服务器控制台
  • 21天网站建设实录深圳招标信息网
  • 晋江网络推广公司北京优化生育
  • 天津开发区网站合肥企业建站系统
  • 营销推广运营咸阳网站建设seo
  • 医院网站建设策划案模板网站外链快速建设
  • 企业网站报价方案模板下载内容管理系统 开源
  • 传统的网站开发模式和mvc网站导航栏垂直
  • 长春网站建设解决方案网站模板手机
  • 北京如何做网站opencms做网站 谁
  • 企业网站找谁做深圳数字展厅
  • 佛山网站营销推广河北优化网站获客qq
  • wordpress站点转移上海松江品划做网站
  • 网站如何投放广告泰然建设网站
  • 网站后端用什么软件做泉州百度广告
  • 网站商城建设的维度如何自己制作网页
  • 江苏省省建设集团网站前程无忧企业官方网站
  • 淘宝网站品牌设计网站首页布局自适应
  • 青岛网站建设方案服务四川省城乡建设厅官方网站
  • 三亚文明城市建设服务中心报名网站wordpress怎么做301跳转
  • 福州企业网站建设推广电子商务专业怎么样
  • html5网站模板 站长网南宁企业建站程序
  • 学做宝宝衣服网站网站建设与网页制作教程