首先,app 和电商是两个不同维度的东西吧,app 算技术领域,电商算业务,按这个来说年限有点怪怪的。
其次,业务延续性确实不同人有不同的选择。我之前在互联网金融公司,里面的小伙伴出来有有继续在金融领域的,也有换到其他互联网领域的,甚至转行做产品或者其他岗位的。
我自己每次跳,虽然一直都是测试领域,但从公司对应业务领域来说差别都挺大。个人感受上,其实不会有太大的 “业务没有延续性” 这方面的担忧,反而会觉得自己的业务观会越来越大,而这个业务观也会帮助自己每次熟悉新领域的时候,更快速能上手和找到关键点。
补充一个点,对某个领域是否深入,呆多长时间只是一个参考值,关键还是是否有持续提升和扩大自己的视野。我在上家公司 3 年多时间,从小组长做到质量团队负责人,视野从只是管小组,变成了整个公司业务的质量,个人感觉对业务的深入度,尤其是对抓关键点的能力(比如那些功能对业务而言更重要),其实会越来越强。而这个能力后面换了公司,还是可以延续的。
包含但不限于这个,DevOps 关注的还是研发流程内部。这些年的实践,我对于提效的理解也有些转变,有点朝着精益的方向。
除了重复事情自动化外,会更多考虑怎么 “简单做”(简单到别人也能做,就可以顺势赋能),甚至 “不用做”(比如基于投入产出比评估来砍/拆需求、降低技术方案复杂度,这样质量风险减少,测试工作量也能对应减少)。
以我这几年做测开的经验, 很多有价值的事情都是需要一定的研发和运维能力才能去做。
这句想特别点个赞!很多时候想要做更有价值的事情,得先自己突破测试的界限。
我们以前遇到过类似场景,自己封装了一个断言函数,大概逻辑是:
1、入参是超时时间、查询 sql 、预期值
2、在超时时间内,每隔 1s 去查数据库的值,并确认值是否符合。不符合就继续查询,符合就 return
3、达到超时时间后的下一次查询,还是不符合,就抛出断言异常
借鉴的是 selenium 的 WebDriverWait
的思路。如果想通用性更强(比如不只是查库,还可以是其它断言),推荐直接引入 awaitility ,这个库就是专门干这个活的。
这个实践挺不错的,把重复繁琐的工作用自动化来提效。
手动筛选映射关系模板,人工核对代码的输出结果跟筛选的结果是否一致
这个部分能否详细说下在这个场景下,人工是怎么测试的验证的?
感觉这个 “筛选”,就是从庞大的映射集关系里,找到 key 和sku_key_list
一样的规则,并把sku_list
里对应的值,和规则里对应的值做一次匹配,得出对应的人可以理解的含义?筛选出这些规则后,后续是怎么测试?
我 2 年多出来的时候,也是差不多这个水平。这个薪酬和年限要求,薪酬不算低了吧。
话说,你那个朋友 9 年经验,这个 1-3 年的岗位也不一定匹配他把,忽略就好。真正要过百万那种高薪,基本都在大厂核心部门 + 高级别岗位。
客气啦,这些我也是和其他人交流 + 自己实践学到的,后面可以来社区多分享交流。
客气了,后面可以在社区持续交流。不仅是技术,也可以是一些提效的小技巧。
很多时候,通用性强(外面各种分享常见的基本都是这类)的工具,成本也不低。针对特定业务特定场景做的一些小工具,小改进,反而效果会更明显。
个人觉得,对于能效领域,工具平台都是辅助工具,关键点还是思想思维。比通过工具来提高测试效率来得更有效的,是通过需求分析、技术设计直接降低工程的复杂度,进而减少测试、开发工作量。
补充一个在实际中用处特别大的平台:环境部署管理平台。
主要提供能力:
1、快速部署单个应用(在部署里面融合流水线做各种卡点)
2、根据当前客户端绑定的环境,自行切换路由能力(比如完整系统是 a+b+c,本次需求只改了 b,那这个需求专属环境只需要部署 b,a 和 c 自动用公共环境里已有的)
这个平台在团队并行需求多的情况下,能非常有效提升效率,彻底解决测试环境少了不够用、多了部署和维护成本高的问题。
都是挺好想法。前 4 个点也很认同。现在为了 kpi 而做的平台已经越来越少了,也是一个好事。
个人觉得除了看到有这些业内有成功经验的能效平台外,还需要关注是否适合公司当前的业务,落地的 ROI(投入产出比)是否合适。上面提到的平台很多都是外部分享的常客,但有不少目前没有对应的可开箱即用的开源实现,所以对于不少公司来说,需要自行开发的部分不少,成本还是不低的。
比如流量回放平台
主要成本:找到运维 + 开发进行对应系统调整及接入,以及结果比对里如何有效降噪。由于业内目前没有什么开箱即用级别的开源工具,需要自行整合和适配自己公司的基础框架,开发成本会比较高
主要收益:对于已有流量的接口,可以快速构造对应的真实测试用例
ROI 最高的场景:接口不变情况下的系统重构/代码持续优化
总结:如果接下来有大型的系统重构,或代码持续优化是开发团队比较关注的点,且一直会占据一定的比例,带来一定测试工作量,适合使用。如果没这类场景,或者这类场景比重较低(基本都在做新功能,不怎么还技术债),投入产出比不高。
比如代码覆盖率平台
主要成本:测试环境的覆盖率数据接入、覆盖率统计平台开发、个别个性化能力的开发(比如增量覆盖率、多版本覆盖率合并等)、测试人员额外投入时间分析未覆盖点风险。
主要收益:覆盖率可以作为测试范围是否充分的参考指标;未覆盖行的分析可以辅助发现漏测点。
ROI 最高的场景:测试全面度的指标统计、测试末期的未测试点补充
总结:团队对质量要求较高,不仅要求需求点都有测试,且要求开发的一些功能点(比如异常处理流程)也需要覆盖时,收效会比较明显。如果还没到达这个阶段,或者相比精细化测试更关注快速交付,不一定适合。
有两种方式。
一种是你说的,去查询数据库。
另一种也是你目前在做的,使用查询接口。
两种都可以,相对来说查询数据库会更自由(因为系统可能没提供查询接口,或者部分内部字段客户端/前端用不到,查询接口不会暴露出来)。不过如果查询接口可以满足,用查询接口是最好的,后续有线上接口拨测需要的时候,可以直接复用(运维是不大可能为了这个,给你开线上数据库的权限的)
至于分页这个,抽验几个点就可以了:
1、总页数对不对
2、改变当前页数,数据是否有对应变化
实际开发写代码实现分页逻辑,这方面都有对应的库(可以百度下 mysql 分页查询),库的写法对了就很稳了,配置不对上面两个数据其中一个基本都会出问题,也很容易发现。
其实你说的东西是有一定道理的,比如从看技术书开始,学习要不断否定自己,这些我都认同。确实相比算法这类技术要求很高的岗位,自己还很菜。
只是这个表述方式有点太居高临下的感觉了,甚至略带点嘲讽(特别是 哎,挺难的,我这要求确实太高了
这一句,可能希望起到激将法,但可能听起来更像是打上了你们就是做不到的标签)。这语气更多会引起反抗,而非反思。
辩论不等于争论,更不等于要说服别人哈。个人理解,辩论的目标不是要辩赢谁,而是要看到事物的两面性,让大家对这个问题产生新的理解。
主要是看到大家戾气有点强,求学态度慢慢变弱了,所以才想搞下这样的活动。我比较喜欢 “三人行必由我师” 这种态度。
至于鄙视这个点,其他人怎么鄙视测试那是其他人的观点,也确实会天外有天人外有人。单纯语言上的反驳收效是很微小的,自己持续想办法变强,证明自己就好了。
看来涉及到了不少 pytest 特性,这块不大熟悉,先退下了。
看看其他同学有没有什么建议把。
额,从你的截图看,你这个代码里,self.staue 没可能是 False 。你这里逻辑是不是没贴全?
1、初始值是 True
2、后续改变值的语句 self.statue = outcome.success
,是放在了 if outcome.success
里面的,意味着这里面的 outcome.success
值如果是布尔值,那也必定是 True
所以,你在后面继承的 B 类里拿到 self.statue 是 True ,说明不了这个 True 就是第二个位置给的。
然后,也没太看懂你这里加个 self.statue 且想要被子类拿到的目的是什么,想实现什么功能?这块可以说下不?
PS:statue 是不是拼错了?状态的英文应该是 status
这个要看公司。没法一概而论。也有的直接按各个团队人员比例来裁。
你这个方法,fun4() 能拿到的只有 init 里配置的初始值,拿不到 fun2() 里面改变后新的属性值吧。fun2() 改变的是 class A 对象里面的内部属性,而 class B 继承的是类,而非对象。
而且即使能实现,你这块设计也会导致使用时比较混乱。因为你这个属性值有可能在 class A 的任何方法里被改动,而且这个 class A 极有可能是在其它文件里的,对于 class B 的使用人员来说,这个属性值是一个难以预测的值,要合理使用还得看完 class A
建议可以考虑下,修改 class A ,提供这个属性值的 get 方法。然后 class B 通过获取 class A 实例化后的对象,来获取对象里面的属性(可以通过单例模式来保障 class A 只会有一个对象,避免存在多个对象拿错了)。而不是通过继承去获取。继承只能继承类,复用里面类相关的资料(如方法、类变量这类代码里本身就有写好的内容),但没法继承一个对象的(也就是用不了任何运行时才创建或改变的内容)。
或者可以去掉这些 class A 之类的脱敏,具体说下你这个场景是什么,这样才能更好地给合适的建议。
1、这种算是业务逻辑。因为不能保障和看到的接口文档强一致,不过这类逻辑如果是非常简单的,也建议直接 review 代码。个人觉得,不是很值得为了一个超简单且不怎么改的业务逻辑,去维护一个用例。
2、这种我理解就是多接口调用测试用例了,也就是上面很多同学说的接口集成测试,或者叫流程型用例(对比单接口用例)。一般做法是在 setup 里面调了 A 接口后,从 A 接口的返回值提取需要的参数。然后在 test 方法里把参数带上去请求 B 接口。
PS:你这种不是 callback 吧?个人理解的 callback 是被调用方在完成自己需要做的东西后,主动发起某个调用方明确要求的操作,主要用于异步非阻塞型任务。你这个 B 接口要 A 接口返回值,前提是 A 接口已经有返回,所以是同步阻塞型的
比如金融业务里常见的付款,A 系统调用 B 系统提供的付款接口,并要求在 B 系统处理完毕后给某个指定的 url 发一个请求,表示处理完毕。B 系统会在收到后立即放到一个类似队列的位置缓存,然后返回已收到(此时还没开始处理),此时这个 api 调用已经结束了。接下来 B 会做一系列操作(比如请求第三方等),全部操作完毕后,再调用最前面 A 系统给的一个指定 url,通知自己已经处理完毕。这个在最后主动调用 A 系统给的 url,我理解才是 api callback 。
同步异步、阻塞非阻塞的解释,建议看这篇文章,讲得非常清晰:https://mp.weixin.qq.com/s/CvImJ5Ab1J7KiKAhV0BuAQ
发帖提示什么?
以下均为个人观点哈
比如 url 错误返回 404,大部分情况是 web 框架(如 springmvc)就自动返回的,开发啥都不用写,或者写一次就可以永久使用。这种个人觉得不需要测试
但也有的 url 是直接通配符匹配后,在具体开发写的业务逻辑里面进一步处理的(比如 path 参数,/user/{userId}/info
这类,实际 url 会是 /user/1/info
,也会是 /user/2/info
),那就要测试 url 里面 userId 存在、不存在 2 种场景。
一般异常场景,会区分为业务逻辑异常/非业务逻辑异常。非业务逻辑异常主要是由框架直接校验的(如某某参数不能为空,swagger 或者 jsr303 注解,controller 定义接口的时候就可以一并完成校验了),这类抽查或者通过 review 代码确认有没有问题,更高效;业务逻辑异常则是具体的内部逻辑,这部分一般会是复杂度比较高的,做接口测试会更高效。
如果拿的方式是找后端拿(比如不走 api 取,但是走 mq 取,甚至直接查库),那你就找后端拿
如果拿的方式是本身自己内置(比如本身有字典表或者对应常量),那就直接写死在你代码里
至于你说的 “自己写一个 mock 的接口” ,不是很明白。你还是把你的完整场景说清楚吧,现在说一半不说一半,看不大懂。
我们这边实际用远程启动好 wda 服务时的日志:
2021-06-18 18:55:34:442 [Appium] Welcome to Appium v1.21.0
2021-06-18 18:55:34:443 [Appium] Non-default server args:
2021-06-18 18:55:34:444 [Appium] port: 20000
2021-06-18 18:55:34:444 [Appium] sessionOverride: true
2021-06-18 18:55:34:444 [Appium] logFile: public/serverLog/appium_20000_2021-06-18_18-55-33.log
2021-06-18 18:55:34:444 [Appium] localTimezone: true
2021-06-18 18:55:34:461 [Appium] Appium REST http interface listener started on 0.0.0.0:20000
2021-06-18 18:55:34:634 [HTTP] --> GET /wd/hub/status
2021-06-18 18:55:34:634 [HTTP] {}
2021-06-18 18:55:34:635 [GENERIC] Calling AppiumDriver.getStatus() with args: []
2021-06-18 18:55:34:636 [GENERIC] Responding to client with driver.getStatus() result: {"build":{"version":"1.21.0"}}
2021-06-18 18:55:34:639 [HTTP] <-- GET /wd/hub/status 200 5 ms - 68
2021-06-18 18:55:34:640 [HTTP]
2021-06-18 18:55:35:066 [HTTP] --> POST /wd/hub/session
2021-06-18 18:55:35:066 [HTTP] {"desiredCapabilities":{"noReset":true,"xcodeOrgId":"F7YWW93M6T","bundleId":"xxx","skipLogCapture":true,"deviceName":"iPhone6s","wdaLocalPort":25000,"webDriverAgentUrl":"http://192.168.25.12:20474","waitForQuiescence":false,"newCommandTimeout":43200,"platformVersion":"14.5.1","automationName":"XCuiTest","useNewWDA":false,"wdaStartupRetries":0,"platformName":"iOS","udid":"xxx","wdaConnectionTimeout":1800000,"autoAcceptAlerts":true},"capabilities":{"firstMatch":[{"appium:autoAcceptAlerts":true,"appium:automationName":"XCuiTest","appium:bundleId":"xxx","appium:deviceName":"iPhone6s","appium:newCommandTimeout":43200,"appium:noReset":true,"platformName":"ios","appium:platformVersion":"14.5.1","skipLogCapture":true,"appium:udid":"xxx","appium:useNewWDA":false,"waitForQuiescence":false,"appium:wdaConnectionTimeout":1800000,"appium:wdaLocalPort":25000,"appium:wdaStartupRetries":0,"appium:webDriverAgentUrl":"http:/...
2021-06-18 18:55:35:066 [W3C] Calling AppiumDriver.createSession() with args: [{"noReset":true,"xcodeOrgId":"F7YWW93M6T","bundleId":"xxx","skipLogCapture":true,"deviceName":"iPhone6s","wdaLocalPort":25000,"webDriverAgentUrl":"http://192.168.25.12:20474","waitForQuiescence":false,"newCommandTimeout":43200,"platformVersion":"14.5.1","automationName":"XCuiTest","useNewWDA":false,"wdaStartupRetries":0,"platformName":"iOS","udid":"xxx","wdaConnectionTimeout":1800000,"autoAcceptAlerts":true},null,{"firstMatch":[{"appium:autoAcceptAlerts":true,"appium:automationName":"XCuiTest","appium:bundleId":"xxx","appium:deviceName":"iPhone6s","appium:newCommandTimeout":43200,"appium:noReset":true,"platformName":"ios","appium:platformVersion":"14.5.1","skipLogCapture":true,"appium:udid":"xxx","appium:useNewWDA":false,"waitForQuiescence":false,"appium:wdaConnectionTimeout":1800000,"appium:wdaLocalPort":25000,"appium:wdaStartupRetries":0,"appium:webDriverAgentUrl":"http://192.168.25.12:20474","appium:xc...
2021-06-18 18:55:35:067 [BaseDriver] Event 'newSessionRequested' logged at 1624013735067 (18:55:35 GMT+0800 (China Standard Time))
2021-06-18 18:55:35:069 [BaseDriver] The following capabilities are not standard capabilities and should have an extension prefix:
2021-06-18 18:55:35:070 [BaseDriver] skipLogCapture
2021-06-18 18:55:35:070 [BaseDriver] waitForQuiescence
2021-06-18 18:55:35:729 [Appium] Appium v1.21.0 creating new XCUITestDriver (v3.43.0) session
2021-06-18 18:55:35:729 [Appium] There are no active sessions for cleanup
2021-06-18 18:55:35:731 [BaseDriver] W3C capabilities and MJSONWP desired capabilities were provided
2021-06-18 18:55:35:731 [BaseDriver] Creating session with W3C capabilities: {
2021-06-18 18:55:35:731 [BaseDriver] "alwaysMatch": {
2021-06-18 18:55:35:731 [BaseDriver] "platformName": "ios",
2021-06-18 18:55:35:732 [BaseDriver] "appium:skipLogCapture": true,
2021-06-18 18:55:35:732 [BaseDriver] "appium:waitForQuiescence": false,
2021-06-18 18:55:35:732 [BaseDriver] "appium:autoAcceptAlerts": true,
2021-06-18 18:55:35:732 [BaseDriver] "appium:automationName": "XCuiTest",
2021-06-18 18:55:35:732 [BaseDriver] "appium:bundleId": "xxx",
2021-06-18 18:55:35:732 [BaseDriver] "appium:deviceName": "iPhone6s",
2021-06-18 18:55:35:732 [BaseDriver] "appium:newCommandTimeout": 43200,
2021-06-18 18:55:35:732 [BaseDriver] "appium:noReset": true,
2021-06-18 18:55:35:732 [BaseDriver] "appium:platformVersion": "14.5.1",
2021-06-18 18:55:35:732 [BaseDriver] "appium:udid": "xxx",
2021-06-18 18:55:35:732 [BaseDriver] "appium:useNewWDA": false,
2021-06-18 18:55:35:733 [BaseDriver] "appium:wdaConnectionTimeout": 1800000,
2021-06-18 18:55:35:733 [BaseDriver] "appium:wdaLocalPort": 25000,
2021-06-18 18:55:35:733 [BaseDriver] "appium:wdaStartupRetries": 0,
2021-06-18 18:55:35:733 [BaseDriver] "appium:webDriverAgentUrl": "http://192.168.25.12:20474",
2021-06-18 18:55:35:733 [BaseDriver] "appium:xcodeOrgId": "F7YWW93M6T"
2021-06-18 18:55:35:733 [BaseDriver] },
2021-06-18 18:55:35:733 [BaseDriver] "firstMatch": [
2021-06-18 18:55:35:733 [BaseDriver] {}
2021-06-18 18:55:35:733 [BaseDriver] ]
2021-06-18 18:55:35:733 [BaseDriver] }
2021-06-18 18:55:35:742 [BaseDriver] Session created with session id: 1f9c9767-7842-4635-8610-7adc9eee6738
2021-06-18 18:55:35:761 [XCUITest] Current user: 'lizhi'
2021-06-18 18:55:35:774 [XCUITest] Available devices: xxx
2021-06-18 18:55:35:775 [XCUITest] Creating iDevice object with udid 'xxx'
2021-06-18 18:55:35:775 [XCUITest] Determining device to run tests on: udid: 'xxx', real device: true
2021-06-18 18:55:35:775 [XCUITest] Normalized platformVersion capability value '14.5.1' to '14.5'
2021-06-18 18:55:35:776 [BaseDriver] Event 'xcodeDetailsRetrieved' logged at 1624013735775 (18:55:35 GMT+0800 (China Standard Time))
2021-06-18 18:55:35:776 [BaseDriver] Event 'appConfigured' logged at 1624013735776 (18:55:35 GMT+0800 (China Standard Time))
2021-06-18 18:55:35:776 [BaseDriver] Event 'resetStarted' logged at 1624013735776 (18:55:35 GMT+0800 (China Standard Time))
2021-06-18 18:55:35:777 [XCUITest] Reset: fullReset not set. Leaving as is
2021-06-18 18:55:35:777 [BaseDriver] Event 'resetComplete' logged at 1624013735777 (18:55:35 GMT+0800 (China Standard Time))
2021-06-18 18:55:35:777 [WebDriverAgent] Using WDA path: '/Users/lizhi/.nvm/versions/node/v12.22.1/lib/node_modules/appium/node_modules/appium-webdriveragent'
2021-06-18 18:55:35:777 [WebDriverAgent] Using WDA agent: '/Users/lizhi/.nvm/versions/node/v12.22.1/lib/node_modules/appium/node_modules/appium-webdriveragent/WebDriverAgent.xcodeproj'
2021-06-18 18:55:35:782 [XCUITest] 'skipLogCapture' is set. Skipping starting logs such as crash, system, safari console and safari network.
2021-06-18 18:55:35:782 [XCUITest] Setting up real device
2021-06-18 18:55:36:266 [DevCon Factory] Requesting connection for device xxx on local port 20474
2021-06-18 18:55:36:266 [DevCon Factory] Cached connections count: 0
2021-06-18 18:55:36:266 [DevCon Factory] Successfully requested the connection for xxx:20474
2021-06-18 18:55:36:267 [XCUITest] Starting WebDriverAgent initialization with the synchronization key 'XCUITestDriver'
2021-06-18 18:55:36:268 [XCUITest] Trying to start WebDriverAgent 1 times with 10000ms interval
2021-06-18 18:55:36:268 [BaseDriver] Event 'wdaStartAttempted' logged at 1624013736268 (18:55:36 GMT+0800 (China Standard Time))
2021-06-18 18:55:36:268 [WebDriverAgent] Using provided WebdriverAgent at 'http://192.168.25.12:20474'
2021-06-18 18:55:36:270 [WD Proxy] Matched '/status' to command name 'getStatus'
2021-06-18 18:55:36:270 [WD Proxy] Proxying [GET /status] to [GET http://192.168.25.12:20474/status] with no body
2021-06-18 18:55:36:287 [WD Proxy] Got response with status 200: {"value":{"message":"WebDriverAgent is ready to accept commands","state":"success","os":{"testmanagerdVersion":28,"name":"iOS","sdkVersion":"14.5","version":"14.5.1"},"ios":{"ip":"192.168.17.178"},"ready":true,"build":{"time":"May 25 2021 19:44:41","productBundleIdentifier":"com.facebook.WebDriverAgentRunner"}},"sessionId":null}
2021-06-18 18:55:36:288 [BaseDriver] Event 'wdaSessionAttempted' logged at 1624013736288 (18:55:36 GMT+0800 (China Standard Time))
2021-06-18 18:55:36:288 [XCUITest] Sending createSession command to WDA
2021-06-18 18:55:36:289 [WD Proxy] Matched '/session' to command name 'createSession'
2021-06-18 18:55:36:289 [WD Proxy] Proxying [POST /session] to [POST http://192.168.25.12:20474/session] with body: {"capabilities":{"firstMatch":[{"bundleId":"xxx","arguments":[],"environment":{},"eventloopIdleDelaySec":0,"shouldWaitForQuiescence":false,"shouldUseTestManagerForVisibilityDetection":false,"maxTypingFrequency":60,"shouldUseSingletonTestManager":true,"shouldTerminateApp":true,"defaultAlertAction":"accept"}],"alwaysMatch":{}}}
2021-06-18 18:55:37:911 [WebDriverAgent] Parsed BUILD_DIR configuration value: '/Users/lizhi/.nvm/versions/node/v12.22.1/lib/node_modules/appium/node_modules/appium-webdriveragent/DerivedData/WebDriverAgent/Build/Products'
2021-06-18 18:55:37:911 [WebDriverAgent] Got derived data root: '/Users/lizhi/.nvm/versions/node/v12.22.1/lib/node_modules/appium/node_modules/appium-webdriveragent/DerivedData/WebDriverAgent'
2021-06-18 18:55:38:785 [WD Proxy] Got response with status 200: {"value":{"sessionId":"BE97DA3B-EB3D-4D16-8231-A8D18AA33E64","capabilities":{"device":"iphone","browserName":" ","sdkVersion":"14.5.1","CFBundleIdentifier":"com.apple.springboard"}},"sessionId":"BE97DA3B-EB3D-4D16-8231-A8D18AA33E64"}
2021-06-18 18:55:38:785 [WD Proxy] Determined the downstream protocol as 'W3C'
2021-06-18 18:55:38:786 [BaseDriver] Event 'wdaSessionStarted' logged at 1624013738786 (18:55:38 GMT+0800 (China Standard Time))
2021-06-18 18:55:38:786 [BaseDriver] Event 'wdaStarted' logged at 1624013738786 (18:55:38 GMT+0800 (China Standard Time))
2021-06-18 18:55:38:786 [XCUITest] Skipping setting of the initial display orientation. Set the "orientation" capability to either "LANDSCAPE" or "PORTRAIT", if this is an undesired behavior.
2021-06-18 18:55:38:786 [BaseDriver] Event 'orientationSet' logged at 1624013738786 (18:55:38 GMT+0800 (China Standard Time))
2021-06-18 18:55:38:786 [BaseDriver] The value of 'elementResponseAttributes' setting did not change. Skipping the update for it
2021-06-18 18:55:38:787 [BaseDriver] The value of 'shouldUseCompactResponses' setting did not change. Skipping the update for it
2021-06-18 18:55:38:787 [Appium] New XCUITestDriver session created successfully, session 1f9c9767-7842-4635-8610-7adc9eee6738 added to master session list
2021-06-18 18:55:38:788 [BaseDriver] Event 'newSessionStarted' logged at 1624013738787 (18:55:38 GMT+0800 (China Standard Time))
2021-06-18 18:55:38:788 [W3C (1f9c9767)] Cached the protocol value 'W3C' for the new session 1f9c9767-7842-4635-8610-7adc9eee6738
2021-06-18 18:55:38:788 [W3C (1f9c9767)] Responding to client with driver.createSession() result: {"capabilities":{"webStorageEnabled":false,"locationContextEnabled":false,"browserName":"","platform":"MAC","javascriptEnabled":true,"databaseEnabled":false,"takesScreenshot":true,"networkConnectionEnabled":false,"platformName":"ios","skipLogCapture":true,"waitForQuiescence":false,"autoAcceptAlerts":true,"automationName":"XCuiTest","bundleId":"xxx","deviceName":"iPhone6s","newCommandTimeout":43200,"noReset":true,"platformVersion":"14.5.1","udid":"xxx","useNewWDA":false,"wdaConnectionTimeout":1800000,"wdaLocalPort":25000,"wdaStartupRetries":0,"webDriverAgentUrl":"http://192.168.25.12:20474","xcodeOrgId":"F7YWW93M6T"}}
2021-06-18 18:55:38:789 [HTTP] <-- POST /wd/hub/session 200 3723 ms - 736
不过我们是在 mac 下运行的,不会出现你上面日志里的错误:[WebDriverAgent] Cannot retrieve WDA build settings. Original error: spawn xcodebuild ENOENT
。建议你根据日志看下源码,看是不是 appium 会不会不管是否要不要启动 wda ,都要检测 xcodebuild 是否存在?
如果是,要不改源码,要不可以往 path 搞个假的 xcodebuild ,让输出符合 appium 检测结果就行。
可能我表述也不够清晰。我不是说不涉及这些规范,而是这些规范并不像是导致 迁云时间跨度长 的根本原因。 “因为迁云时间跨度太长了,所以我们要落实代码规范/code review”,这个因果关系不够明确,也说服不了别人。
对于项目跨度时间长,因素会很多。而且很多时候这些地方缺少的不是规范或流程,而是大家的意识。好的程序员,并不会因为规范的缺失而写出很烂的代码,因为规范已经在他意识里面了,没规范他自己也会去制定规范。而改变意识成本是很高的,周期也比较长,需要找好节奏,循序渐进,并且每一步都找到合适切入点。
明天回公司看下 appium 版本,感觉像是 appium 版本不同导致的问题。
听你描述,学 java 至少可以看开发代码,修下小 bug 之类的。学 go 好像能做的事情更少?
感觉你的问题和原因有点对不上呀。迁云我理解更多是运维部署层面的,最多和发布管理有一些关系,前面的这些不规范和迁云有什么关系呢?比如代码命名不规范,主要影响其他人的阅读和理解,但不会直接造成缺陷的。建议要先复盘清楚,到底根本原因是在哪里,没有解决根因,其他改进都是吃力不讨好。
另外,要特别留意,这些规范,限制的不仅自己下面的测试团队,更多是开发、运维这些兄弟团队。先和大家沟通好达成共识,这个是大前提。
我按我经历过的大概写下吧:
阿里、google 这些大公司都有各个语言的代码规范白皮书这类文档分享出来的,各个语言自己也有自己的一些推荐规范(比如 idea 自带的规则基本是基于这些规范),可以基于这些来调整。我们之前具体的调整是由一些资深开发 + 测试组成的技术委员会来操刀,保障调整的有效性。而且这些人参与了制定过程,后面落地认同感也更强,更容易推进落地。
同时也可以搞一些 bad case 之类的文化活动,分享一下某些不规范的写法会导致什么样的 bug ;或者组织大家看看 clean code 这本书,对怎么写好代码有更好的认识。
这个核心就是分支模型了。一般主流就几个,主干开发 + 主干发布,分支开发 + 主干发布,主干开发 + 分支发布。一般需求并行比较多的,采用 分支开发 + 主干发布 会比较多。然后配合 gitlab 提供的 protect 分支特性,可以把主干保护起来,只有 master 权限才能合并,普通开发改不了,只能在自己的分支上修改,然后提 merge request(后面缩写为 MR)来申请合并。
master 一般由团队里对系统比较熟悉的人来做,这样在 MR 的时候做的 code review ,会更有效。同时 MR 也可以定制补充一些自动检查项(如前面大家提到的 sonar 、单测这类),检查结果直接呈现在 MR 中,作为 code review 的参考。
这里面东西比较多,比如 review 的时机(赶早不赶晚,谁都无法认真 review 改动行数过千的改动),review 的方式(评审人和写代码的人一起的方式,如 review 会议、结对 review;不在一起的方式,如前面提到的用 MR review ),review 的限制程度(阻塞式,必须 review 通过才能合并和提测,节奏相对慢的用得比较多;非阻塞式,可以提测后再 review,节奏快的更适用)。这块建议微信公众号搜索下吧,以前看到过挺多好文章的。
我们实际落地更多是提测后测试去阅读代码(我们一般不叫 review ),有问题会和开发沟通确认。通过阅读代码可以了解实现逻辑,也能更直接的找到一些问题,比如空指针隐患、if else 的场景不够全、事务性操作没有包到一个事务里等。
不知道你们那边运维发布相关的基础设施做到什么程度,是已经做到了一个带审批流程的平台上,还是只是一个 jenkins job ,还是更人工的。如果想 QA 在这个层面上做很大的限制(比如二次确认开发有没有在最后时刻自己加料啥的),那需要在发布的审核流程里加上 QA 这个环节,QA 审核通过才能到实际部署这个步骤。
我们实际落地,审核流程会有 QA 环节,并且 QA 不能只是管审核,还需要在上线后和开发、产品一起通过线上测试/指标监控等手段,确认上线后没问题,为最终上线结果负责。
代码规范、分支规范、code review 这些,本质上更多是在开发阶段做的事情,如果本身开发都没这方面经验甚至想法,需要长期灌输慢慢接受。
要逐步落地,建议可以先从线上问题复盘改进开始,一方面都出事故了,大家容易配合推进;另一方面这些问题一般也是破坏性比较大,最需要解决的问题。
个人经验,任何规范都是约束,都是会产生额外成本的,而且落地最终要靠的还是人。所有的要推行的规范,一定要能解决某些目前存在的实际问题,并和大家取得共识。切勿为了规范而规范,最后变成一张废纸。
PS:正常一个稍微大一点的开发团队,分支规范应该是最基础的协作基础,不可能没有的。建议你先和开发团队沟通下,了解下对于一个新开发进入团队,他们会教些什么,这里面一般就会有代码规范、分支规范这些了。