不知道具体组织情况,仅针对提到的 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 跨域” 都能找到不少相关文章,很常见的问题。
截个图看看?从你发的信息看,这个控件是 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 传的数组内存地址
看懂了,讲的应该是基本类型和引用类型,以及两种类型在赋值的时候值是怎么传递的。
提几个和我理解不大一样的点:
1、定时器(Synchronizing Timer),这个应该是集合点吧,目的是模拟瞬间高压力的场景(几毫秒内直接指定数量的请求过来,造成短暂高压力)。定时器对应英文是 timer ,有好几种不同的定时器的,统一叫定时器好像不大好
2、ForEache
、Contrlooer
两个好像都拼写错误了?。
3、头管理器 不知道你具体指的是哪个?有 http header manager 和 http cookie manager ,你的描述像是 http cookie manager ,但直译的话头管理器应该是 http header manager 。
所以让她自己亲身体验一遍,就知道自己认知差异了。
表里查出来的结果不一定是接口反映的结果
这个认同,确实会有这种情况。不过确实有的业务操作后存储的数据不会有对应查询接口的,这类数据可能通过其他手段和其他系统交互(比如直接过来取数/通过 MQ 之类的直接发消息)。还是具体情况具体分析吧,上升到 “原则” 感觉有点过了。
多个接口比例,个人理解本质上是根据业务场景确定的。
已上线:可以基于线上数据获取,比如流量录制,或者通过日志来分析。而且要注意想办法多拿几次数据,确定要有哪几种场景。
未上线:找项目相关的开发、产品、运营一起评估下用户最常用的场景,分析场景里接口调用情况,然后把它作为一个大致的基准。
虽然有点卖广告,但还是推荐看看高楼老师极客时间的《性能测试实战 30 讲》,里面 13、14 讲就是特别讲这块的,个人觉得也是相对科学的方法。