• 不知道具体组织情况,仅针对提到的 3 个能力分享下自己大概想到的:

    专业能力:内部高级别的同学做定期分享培训、协同外部一些机构提供培训学习机会(如批量购买极客时间课程、设立技术图书库等)、设立专业能力强人之类的奖项定期奖励

    创新能力:参加外部会议(如 MTSC、沙龙等)了解外部情况、设立创新能力强人之类奖项、日常工作安排能挤部分时间让能人去做一些创新探索性工作

    协同能力:团建、项目复盘、设立技术 PM 统筹他参与需求的全流程进度及风险,为项目按时完成负责,并定期有对应优秀技术 PM 奖项进行奖励(个人觉得,为项目负责的想法是协同的前提,这个技术 PM 能把想法变为职责,让大家去突破。老想着是别人的事自己不去管,容易导致只管自己,协同效率低下)

  • leetcode

  • 曾经想问大佬练算法题有没有用,想了下还是自己先练下再问吧。

    这个点赞!

    对于有没有用这个话题,个人感受上来讲是有用的,主要是锻炼编程思维和代码熟练度,也让自己对写代码更自信。

    只是从实际工作上,更多时候关键点是是否使用了适当的框架和用法是否正确,很多逻辑都是比较简单的,类似算法题里面这种复杂度的问题比较少,所以直接改变当前工作这种感觉会相对弱一些,所以容易有 “面试造火箭,进来拧螺丝” 的感觉吧。

  • 这个问题略大,不知道怎么回答你。以自己理解简单说下把:

    首先需求只有个 峰值 20w 用户 ,是不能直接转化为场景的。需要分析抢券这个场景涉及哪些接口请求(比如查券接口 - 抢券接口),然后这些接口请求的频率大概会多高(比如查券可能一秒一次,抢券从头到尾只有一次),把需求转换为抢券时各个接口大概每秒会承受多少次请求,即要达到多少 tps,接口请求之间比例大概多少这些。这些最好和后端开发沟通下,他们对自己系统最熟悉

    建议可以买些书或者极客时间的课程看下,这样效果才好。个人推荐极客时间高楼老师的课,讲得比较简单易懂。

  • 根据日志直译,10 秒内没有获取到界面元素树根节点信息。

    一般多见在一些动态界面上,你公众号具体啥内容,可以补充一下相关信息?

  • java 为主,和开发保持一致,便于查看开发代码逻辑。

  • 额,你这个 java 例子,测试用例还是只有 kotlin 的。我指的是测试用例就是 java 的。

    虽然 kotlin 只要有 idea 都很便捷地跑起来,但还得临时学一些语法才知道怎么改里面的内容。如果有直接 java 版会好很多。

  • 针对这个首次打卡的用例,setUp 的时候注册个新账号。其他的不变,这样改动会不会少点?

  • 好,加了仓库后好了。感谢

    我特意再限制了只跑 util 包里的,避免依赖其他东西跑不出来。看跑出来结果还有些效果,部分空指针没做好处理的有发现了。但也有一些无效的失败,比如文件名是随机的,导致文件不存在,文件 io 操作报异常导致失败;或者 json 格式错误,导致 Json 解析失败。

    从目前情况看,会有一定的误报,测试结果还是得人工二次确认。找空指针或者数组越界有一定效果,但业务逻辑就基本都不怎么能校验到了。

    PS:建议给些用 java + maven 的例子? kt + gradle 在 android 比较流行,但非 android 相对比较少。

  • 不清洗数据的话,可以每次都用新数据吗?比如每次注册个新账号,这样比较简单。

  • 对 kotlin 版本啥的有要求么?拿个开源项目加上文档里给的测试代码试了下,没能跑起来

    对应项目地址:https://github.com/chenhengjie123/AgileTC/tree/try-randunit ,分支是 try-randunit 。

    运行方式是直接在 idea 中点击测试用例前面的执行按钮触发执行。

    错误提示:

    java.lang.NoClassDefFoundError: org/jeasy/random/EasyRandomParameters
    
        at com.williamfzc.randunit.mock.EasyRandomMocker.genDefaultEasyRandomParameters(EasyRandomMocker.kt:31)
        at com.williamfzc.randunit.mock.EasyRandomMocker.<init>(EasyRandomMocker.kt:23)
        at com.williamfzc.randunit.models.MockModel.<init>(MockModel.kt:31)
        at com.williamfzc.randunit.env.AbstractTestEnv.<init>(AbstractTestEnv.kt:32)
        at com.williamfzc.randunit.env.NormalTestEnv.<init>(NormalTestEnv.kt:21)
        at com.williamfzc.randunit.env.NormalTestEnv.<init>(NormalTestEnv.kt:20)
        at com.xiaoju.framework.SmokeTest.<clinit>(SmokeTest.kt:16)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
        at java.lang.reflect.Method.invoke(Method.java:498)
        at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
        at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
        at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
        at org.junit.runners.Parameterized.allParameters(Parameterized.java:280)
        at org.junit.runners.Parameterized.<init>(Parameterized.java:248)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
        at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
        at org.junit.internal.builders.AnnotatedBuilder.buildRunner(AnnotatedBuilder.java:104)
        at org.junit.internal.builders.AnnotatedBuilder.runnerForClass(AnnotatedBuilder.java:86)
        at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
        at org.junit.internal.builders.AllDefaultPossibilitiesBuilder.runnerForClass(AllDefaultPossibilitiesBuilder.java:26)
        at org.junit.runners.model.RunnerBuilder.safeRunnerForClass(RunnerBuilder.java:59)
        at org.junit.internal.requests.ClassRequest.getRunner(ClassRequest.java:33)
        at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:49)
        at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
        at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
        at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
    Caused by: java.lang.ClassNotFoundException: org.jeasy.random.EasyRandomParameters
        at java.net.URLClassLoader.findClass(URLClassLoader.java:382)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:418)
        at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:355)
        at java.lang.ClassLoader.loadClass(ClassLoader.java:351)
        ... 30 more
    
  • 不知道楼主想要的完整资料,完整到什么程度?

    一般自动化框架需要提供三个层次的能力,核心层(提供用例执行管理能力,比如 testng )、工具层(提供触发关键操作的能力,比如接口测试中的 rest-assured,UI 自动化中的 appium、selenium)、适配层(【可选】提供用例编写的模板或规范,减少重复提高编写效率。比如提供 excel 或者 yml 写用例的方式)。

    常见组合:
    核心层:testng + reportNG/Allure report/extentreports,或直接 junit(比较少见)
    工具层:rest-assured(调用接口 + 断言一条龙提供)/基于 httpclient 自行封装/基于其他 http 框架自行封装
    适配层:单接口常见用 excel/yml(一般结合 testng 本身提供的 dataProvider 使用),多接口多见直接写代码(代码里区分单接口调用层、多接口业务操作层,用例是通过调用这两层的方法来完成操作)

    因为大多都是自行组装,根据各个团队自身水平来决定框架怎么做,不同层根据需要可以用不同的框架去组合完成。因为这里面用的最多的是 testng ,所以它相关文章会比较多也不奇怪。

  • 能不能说明下,为何用例里会存在这个接口调用两次的情况,是本身为了校验两次调用返回值不同故意这么做,还是别的而原因?

    个人理解,只要能明确区分接口是第一次被调用还是非第一次,这个断言写起来和普通的没啥差别。至于 message 要不要校验,看业务场景中的重要程度吧。一般前端代码逻辑里只会用 code ,不同 code 走不同的逻辑。而 message 一般直接展示,不会针对性做什么业务逻辑的,所以就算有问题,也只影响用户体验,不一定影响具体功能。当然到底是不是这样,最好你问下项目里的开发同学确认下。

  • 额,这问题有点伸手了,直接搜索引擎找 “cookies 跨域” 都能找到不少相关文章,很常见的问题。

    可以看看这篇:https://www.jianshu.com/p/13d53acc124f

  • 截个图看看?从你发的信息看,这个控件是 safari 浏览器的地址栏。地址栏在滑动时会自动收起的,是不是和这个有关?

    PS:不知道你点击地址栏是不是为了设定网页地址,如果是,可以直接用 webdriver 的 api 设定地址的,不用直接点这个地址栏控件。

  • 开发选择红框这个无法打包安装,只能编译

    具体是怎么无法打包安装,有具体截图或者错误信息之类的吗?

    能编译通过,应该就能安装。你用 run test 这样的方式运行,就会自动装上了。装上的标志是手机里面会有一个 WebDriverAgent 的应用,图标类似下图这样:

  • 很赞呀,加个精让更多有需要在 windows 下跑 ios 自动化的同学看到。从评论看,appium 版本是有一定要求的,建议正文里强调一下这个点?

    @codeskyblue tidevice 的 readme 里可以考虑加上这个,引导有需要的同学过来这里了解详细步骤?

  • 个人理解,应该是指那些有自己 toC 的基于互联网的产品的公司把。比如 BAT、美团这类。

    互联网公司比较大的特点是迭代快、时间紧(需要紧急占领市场的项目直接 007 也是会有的)。要做什么功能主要由产品基于运营及用户反馈来设定需求。技术体系基本是客户端(app/h5/小程序)+ 服务端(java 居多)。

    质量上的挑战主要是,在被压缩的测试时间内(是的,被压缩,有的项目会直接按上线时间倒排),怎么把控好风险,保障质量。确保可以按时上线同时不至于出现严重影响用户使用的问题。

  • 可以社区里搜一些性能测试相关文章看看。

    性能测试比较花多杂乱,建议自己不断实践不断学习吧。

  • 说下我的理解

    # 数组是引用类型,所以把[1,2,3]的内存地址引用赋值给info这个变量
    info = [1,2,3]
    
    # 把4个info的内存地址引用,赋值到数组里,然后整个数组的内存地址引用赋值给 userinfo
    userinfo =[info,info,info,info]
    
    # 因为是地址引用,所以 userinfo[2] 实际上对应的是 info 的内存地址,所以 userinfo[2] 等价于 info (其实 userinfo[0]、userinfo[1] 也是一样的,可以用 id(userinfo[0]) 查看对应的内存地址进行比较),这里改了 info 里面第一个元素的值为 "aaa"
    userinfo[2][0]="aaa"
    
    # 最终结果:['aaa', 2, 3] [['aaa', 2, 3], ['aaa', 2, 3], ['aaa', 2, 3], ['aaa', 2, 3]]
    print(info,userinfo)
    

    倒是第一道题掉坑里了,最后的 userinfo 里面没有 'aaaaa' ,因为里面存储的还是原来 info 传的数组内存地址

  • 看懂了,讲的应该是基本类型和引用类型,以及两种类型在赋值的时候值是怎么传递的。

  • jmeter 学习笔记 at April 02, 2021

    提几个和我理解不大一样的点:

    1、定时器(Synchronizing Timer),这个应该是集合点吧,目的是模拟瞬间高压力的场景(几毫秒内直接指定数量的请求过来,造成短暂高压力)。定时器对应英文是 timer ,有好几种不同的定时器的,统一叫定时器好像不大好

    2、ForEacheContrlooer 两个好像都拼写错误了?。

    3、头管理器 不知道你具体指的是哪个?有 http header manager 和 http cookie manager ,你的描述像是 http cookie manager ,但直译的话头管理器应该是 http header manager 。

  • 所以让她自己亲身体验一遍,就知道自己认知差异了。

  • 表里查出来的结果不一定是接口反映的结果

    这个认同,确实会有这种情况。不过确实有的业务操作后存储的数据不会有对应查询接口的,这类数据可能通过其他手段和其他系统交互(比如直接过来取数/通过 MQ 之类的直接发消息)。还是具体情况具体分析吧,上升到 “原则” 感觉有点过了。

  • 多个接口比例,个人理解本质上是根据业务场景确定的。

    已上线:可以基于线上数据获取,比如流量录制,或者通过日志来分析。而且要注意想办法多拿几次数据,确定要有哪几种场景。
    未上线:找项目相关的开发、产品、运营一起评估下用户最常用的场景,分析场景里接口调用情况,然后把它作为一个大致的基准。

    虽然有点卖广告,但还是推荐看看高楼老师极客时间的《性能测试实战 30 讲》,里面 13、14 讲就是特别讲这块的,个人觉得也是相对科学的方法。