目录 start

目录 end |2018-05-24| 码云 | CSDN | OSChina


测试

基础知识

码农翻身: 张大胖和单元测试

测试类别

单元测试

  •  单元测试, 集成测试

【A/B测试】

对照实验,也叫随机实验和 A/B测试 参考来源:知乎问题 | 相关三方平台

A/B测试其实是一种“先验”的实验体系,属于预测型结论,与“后验”的归纳性结论差别巨大。A/B测试的目的在于通过科学的实验设计、采样样本代表性、流量分割与小流量测试等方式来获得具有代表性的实验结论,并确信该结论在推广到全部流量可信。
说句题外话,大量的大数据公司都在尝试通过“后验”结论进行未来行为预测,个人觉得然并卵,主要是因为数据不全、脏数据、随机事件、建模人为因素等等影响,方向无比正确,现实无比残酷

A/B测试的应用场景

  • A/B测试这种方法论的应用非常广泛,这里讨论在Web产品、移动产品、数字广告优化领域的应用。应用场景由小到大可以可以分为:
    • 元素/控件层面
    • 功能层面
    • 产品层面
    • 公司层面
元素/控件层面

灰度发布 和 A/B测试:重要页面的修改和流程上的调优,通过灰度发布到1%或者5%的用户,看其实际对用户的数据影响(访问时间增加、留存提高、下单率提高等),决定此修改到底是100%发布还是被砍掉 Google: 每个月从上百个A/B测试中找到十几个有效方案,月营收提升2%左右,10亿美元的规模 广告位左移一个像素带来X%的增收,左移两个像素带来Y%的亏损 任何产品改动需要A/B测试才能上线 Facebook: 6个月内所有版本完全线上灰度发布,通过不断进行用户流量分割的方式进行实验,获得无Bug口碑

灰度发布就是,先把一部分线上的业务分流到新系统上, 然后看情况, 再判断是否全部上线

功能层面

无论是推荐算法还是定价策略 为了简单理解,说个定价策略,如上图。 一个价格包含这个几个因素:

1.价格区间:
用我最朴素的理解,人类是喜欢折扣的不理性动物:人们明显更乐意花45折买一个价值900块钱的东西而不是花67折买一个价值600块的东西,尽管东西一样,最终价格一样都是400块。
所以你看电商广告都是打折配合几个垫背的低价来卖。。。

2.价格精度:
以前去超市经常能发现2.99元或者8.99,现在都变成2.32或者4.23,这是弄啥嘞?
这里面太多心理学与营销的东西就不说了,在某些情况下,即使几分钱的价格变化对用户转化的影响是巨大的,比如一个东西原来卖400元,那现在改成399还是401可能对总营收的影响并不巨大,但是配合用户转化率的变化,可能营收的差异就天差地别了。

3.价格周期:
伴随着产品迭代、促销等等因素影响,什么时候降价是对自己最有利的策略,完全可以A/B测试来解决

产品层面

A/B测试在产品层面的应用主要是通过“灰度发布”来实现的。 就目前移动端的产品来说,iOS的应用商店审核期是个大大大坑,任何BUG打补丁还得再来一遍,也就意味着补丁的审核期内用户带着BUG使用,这个太致命了,用户的获取成本高的吓人,因为这个流失太不值得了,基于A/B测试的灰度发布更重要的不是优化,而是保护性发布,先通过小流量的实际用户测试,有BUG或者新版本体验不好,可以立即回滚到老版本,简单有效。

公司层面

A/B测试其实也是谷歌管理方法论,具体文章请参考:

相关问题

辛普森悖论(Simpson's Paradox)亦有人译为辛普森诡论,为英国统计学家E.H.辛普森(E.H.Simpson)于1951年提出的悖论,即在某个条件下的两组数据,分别讨论时都会满足某种性质,可是一旦合并考虑,却可能导致相反的结论。
相关:辛普森悖论:诡异的男女比例

大多数的产品或功能上线前都会进行测试,实际上很多的测试行为并不科学,特别是很多定向的用户测试经常会有这个弊端,简单来说,如果新上线的一个功能,所有的研发工程师都说好,那是不是意味着所有的用户都觉得好?很多情况下是否定的。当然这个例子比较简单,实际上很多A/B测试方法并没有考虑到这个问题,以至于最后得出的结论跟实际情况差异巨大。 要解决这个问题,对采样、聚类、流量分割等要求非常的高,这也是为什么A/B测试工具不能像很多统计工具一样,埋个点看数据,再根据数据反推业务逻辑,而是要充分与业务结合,从一开始就应该考虑业务策略,让用户去选择适合其口味的产品。 现在的创业者面临着前所未有的竞争压力,好的想法与用户接受的想法有着各种不可逾越的鸿沟。特别是伴随着激烈的竞争,谁能领先一步可能就变成了赢者通吃的局面。

相关专栏: [A/B]那些年,我们追过的AB Testing (一) | [A/B]那些年,我们追过的AB Testing (二)从“People you may know”到growth hacking


【冒烟测试】

冒烟测试源自硬件行业,对一个硬件或者硬件组件改动后,直接给设备加电,看看设备会不会冒烟,没冒烟,就表示待测组件是通过了测试。
目的是确认软件基本功能正常,可以进行后续的正式测试工作。


什么是TDD

百度百科词条, 简单来讲就是红绿循环, 红 绿 红...
TDD是测试驱动开发(Test-Driven Development)的英文简称,是敏捷开发中的一项核心实践和技术,也是一种设计方法论。
TDD的原理是在开发功能代码之前,先编写单元测试用例代码,测试代码确定需要编写什么产品代码。TDD虽是敏捷方法的核心实践,但不只适用于XP(Extreme Programming),同样可以适用于其他开发方法和过程。

  • 个人理解:引用Mockito框架中的 "when thenReturn" and "when thenThrow“ 由预定输入,运行方法或模块后,需要返回预定的数据或者抛出预定的异常,这就是已经写好了测试
  • 然后根据测试原型,去思考真正的功能代码的实现,当代码实现后,能够通过之前写的测试就代表着一个方法或模块的开发成功,然后开发下一个
  • 要想做到这样的地步,首先基础的环境要思考好,耦合的问题要明确,确定公共模块之后,再一个个的TDD进行开发。一个很好的思想,不用担心你之后的改动会让代码变得丑陋不堪

优点:在任意一个开发节点都可以拿出一个可以使用,含少量bug并具一定功能和能够发布的产品。
缺点:增加代码量。测试代码是系统代码的两倍或更多,但是同时节省了调试程序及挑错时间。

单元测试是用来对一个模块、一个函数或者一个类来进行正确性检验的测试工作。
比如对函数abs(),我们可以编写出以下几个测试用例:
输入正数,比如1、1.2、0.99,期待返回值与输入相同;
输入负数,比如-1、-1.2、-0.99,期待返回值与输入相反;
输入0,期待返回0;
输入非数值类型,比如None、[]、{},期待抛出TypeError。
把上面的测试用例放到一个测试模块里,就是一个完整的单元测试。

TDD实践

java测试驱动开发(TDD)之《井字游戏》

TDD 测试驱动开发

Java程序员修炼之道 测试驱动开发章节

p276.jpg

TDD带来的好处

  • 更清晰的代码 只写需要的代码
  • 更好的设计 有些开发人员管TDD叫测试驱动的设计
  • 更出色的灵活性 TDD会鼓励按接口编码
  • 更快速的反馈 不会直到系统上线才知道bug的存在

红 - 绿 - 重构循环

  • 先编写不能通过测试的红色代码,就是一个简单的思路编写

  • 然后修改,让测试通过,然后完善设计,进行重构编写,又进入红绿阶段,然后再重构

  • 重构是为了通过测试你写的快速实现,重构减轻自己和别人的技术债务(临时凑合出来的设计或代码将来会付出更多的工作)

    • 有了通过测试, 就可以放心的重构,应该实现的业务逻辑就不可能会被忽视
  • 多个测试用例 为了覆盖更多情况

    • 按照TDD风格,就应该为之前编写的测试用例,进行多路径全覆盖,这个测试依然是红绿重构循环。

深入思考 红 绿 重构循环

  • 失败测试(红)
    • 一些开发人员喜欢编写编译失败的测试,喜欢等到绿色步骤才提供实现代码
    • 也有一些开发人员喜欢先把测试调用的方法签名写出来,这样虽然编译能通过,但还是失败
  • 通过测试
    • 这一步应该尽量少写代码,只要能测试通过即可。
  • 重构
    • 许多地方需要重构,一般是: 去掉硬编码的变量,
    • 或把大方法拆分,对于面向对象来说应该遵循 SOLID 原则 解释SOLID原则
    • 可以把通用的设置和拆卸代码提取出来。可以重命名测试,以便于更准确地反应他的意图,根据静态分析工具例如CheckStyle FindBugs p283.jpg
  • 应该尽可能的遵守单个测试循环的开发模型,不要同时开多个测试循环,一堆红色

JUnit

  • 主要的三个特性:
    • 用于测试预期结果和异常的断言, assertEquals()
    • 设置和拆卸通用测试数据的能力, @Before @After
    • 运行测试套件的测试运行器

一个基本的JUnit测试

  • @Before 标记方法, 测试运行前准备测试数据
  • @After 标记方法, 测试运行完成后拆卸测试数据
  • @Test 测试方法 例如:预期的异常@Test(expected=NullPointException.class)

测试技术

测试替身

泛指任何出于测试目的的替换真实对象的假冒对象,为了解决测试代码的依赖项问题。
四种方式: 虚设,伪装,存根,模拟

p286

虚设对象
  • 他是用来填充参数列表,填补那些总也不会用的必填域。大多数情况下,甚至可以传入null,就是把需要的参数虚拟出来
    • 只是为了避免NPE,让代码能跑起来
存根对象
  • 用来代替真实环境对象,需要有做出相同响应的对象,就是存根对象
    • 将一些外部类或三方资源,写一个类,以及对应的方法,来提供测试运行
伪装替身
  • 伪装替身,可以看作是存根的升级。他做的工作几乎是和生产代码是一样的,单位了满足测试需求也会使用便捷的方式
    • 例如 内存数据库HSQLDB 的使用,
模拟对象
  • 存根对象的调用通常会返回形同的结果。所以不能模拟任何与状态有关的行为,模拟对象就能够更好的胜任
    • 在准备要用的模拟对象时,告诉他会有哪些调用,以及对应的相应,模拟会和DI结合更好。可以用一个虚拟的对象,这个对象完全按照已知方式行动
  • 模拟类库:Mockito官网
    • 调用mock()方法创建模拟对象,并将模拟目标类型的class对象作为参数传进去。
    • 然后要把模拟对象需要的行为记录下来,通过 when方法表明要记录哪些方法的行为,然后用thenReturn方法指定期望结果。

书籍推荐