ScalaTest的测试风格

标签: scalatest 测试 | 发表时间:2014-01-13 18:39 | 作者:
出处:http://agiledon.github.com/

ScalaTest几乎已经成为Scala语言默认的测试框架,而在JVM平台下,无论是否使用Scala进行开发,我认为仍有尝试ScalaTest的必要。这主要源于它提供了多种表达力超强的测试风格,能够满足各种层次的需求包括单元测试、BDD、验收测试、数据驱动测试。正如ScalaTest的创建者Bill Venners所说:

A guiding design principle of ScalaTest is that different people on a team should be able look at each others test code and know immediately what’s going on.

ScalaTest is designed to make it easy for you to customize your testing tool to meet your current needs, and for the built-in traits at least, make it easy for anyone who comes along later to read and understand your code.

UT与IT的风格选择

ScalaTest一共提供了七种测试风格,分别为:FunSuite,FlatSpec,FunSpec,WordSpec,FreeSpec,PropSpec和FeatureSpec。这就好像使用相同的原料做成不同美味乃至不同菜系的佳肴,你可以根据自己的口味进行选择。以我个人的偏好来看,我倾向于选择FlatSpec或FunSpec(类似Ruby下的RSpec)来编写单元测试与集成测试。虽然FunSuite的方式要更灵活,而且更符合传统测试方法的风格,区别仅在于test()方法可以接受一个闭包,但坏处恰恰就是它太灵活了。而FlatSpec和FunSpec则通过提供诸如it、should、describe等方法,来规定书写测试的一种模式,例如前者明显的 “主-谓-宾”结构,后者清晰的 分级式结构,都可以使团队的测试更加规范。如下是ScalaTest官方网站的提供的FunSuite、FlatSpec和FunSpec的三种风格样例。

      //FunSuite
import org.scalatest.FunSuite

class SetSuite extends FunSuite {
  test("An empty Set should have size 0") {
      assert(Set.empty.size == 0)
  }
      test("Invoking head on an empty Set should produce NoSuchElementException") {
      intercept[NoSuchElementException] {
          Set.empty.head
      }
  }
}

//FlatSpec
import org.scalatest.FlatSpec

class SetSpec extends FlatSpec {
  "An empty Set" should "have size 0" in {
      assert(Set.empty.size == 0)
  }
      it should "produce NoSuchElementException when head is invoked" in {
      intercept[NoSuchElementException] {
          Set.empty.head
      }
  }
}

//FunSpec
import org.scalatest.FunSpec

class SetSpec extends FunSpec {
  describe("A Set") {
      describe("when empty") {
          it("should have size 0") {
              assert(Set.empty.size == 0)
          }
                  it("should produce NoSuchElementException when head is invoked") {
              intercept[NoSuchElementException] {
                  Set.empty.head
              }
          }
      }
  }
}

至于WordSpec和FreeSpec,要么太复杂,要么可读性稍差,要么惯用法风格有些混杂,个人认为都不是太好的选择,除非你已经习惯了这种风格。

数据驱动测试风格

JUnit对类似表数据的Fixture准备提供了Parameterized支持,但非常不直观,而且还需要为测试编写构造函数,然后定义一个带有@Parameters标记的静态方法。TestNG的DataProvider略好,但通过在测试方法上指定DataProvider的方式,仍然不尽如人意。ScalaTest提供的PropSpec充分利用了Scala函数式语言的特性,使得代码更简单,表达性也更强:

      import org.scalatest._
import prop._
import scala.collection.immutable._

class SetSpec extends PropSpec with TableDrivenPropertyChecks with Matchers {
  val examples =
    Table(
      "set", BitSet.empty, HashSet.empty[Int], TreeSet.empty[Int]
    )
  property("an empty Set should have size 0") {
    forAll(examples) { set =>
      set.size should be(0)
    }
  }
  property("invoking head on an empty set should produce NoSuchElementException") {
    forAll(examples) { set =>
      a [NoSuchElementException] should be thrownBy { set.head }
    }
  }
}

验收测试风格

我们会推荐由PO(或者需求分析人员BA)与测试人员结对编写验收测试的业务场景,然后由开发人员和测试人员结对实现该场景。Cocumber、JBehave、Twist乃至Robot、Fitness都可以用于编写这样的验收测试(Fitness与Robot更接近实例化需求的方式)。这些工具有一个特点是业务场景与测试支持代码完全是分开的。例如Cucumber将业务场景放到feature文件中,而将测试支持代码放到rb文件中。JBehave类似。这样的好处是feature文件很干净,很纯粹,与技术实现没有任何关系,且有利于生成Living Document。然而,这种分离方式在带来良好可读性的同时,也带来维护成本的增加。

ScalaTest在提供类似Feature的验收测试Spec时,并没有将业务场景与测试支持代码分开,而是采用了混合的方式来表现:

      import org.scalatest.{ShouldMatchers, GivenWhenThen, FeatureSpec}

class TVSetTest extends FeatureSpec with GivenWhenThen with ShouldMatchers{
  info("As a TV Set owner")
  info("I want to be able to turn the TV on and off")
  info("So I can watch TV when I want")
  info("And save energy when I'm not watching TV")

  feature("TV power button") {
    scenario("User press power button when TV is off") {
      Given("a TV set that is switched off")
      val tv = new TVSet
      tv.isOn should be (false)

      When("The power button is pressed")
      tv.pressPowerButton

      Then("The TV should switch on")
      tv.isOn should be (true)
    }
  }
}

ScalaTest的FeatureSpec支持常见的Given-When-Then模式。在上面的代码段中,info提供了对Feature的基本描述,然后提供了feature与scenario两个层级。熟悉Cucumber和JBehave的人对此应该不会陌生。测试支持代码直接写在Given、When、Then方法下,因而针对同一个Feature,只产生一个scala文件。这就意味着测试支持代码与自然语言描述是处于同一级的,准确地说,他们其实就属于同一个测试。开发时,PO(或者需求)与测试可以先编写FeatureSpec的骨架,即info-feature-scenario以及Given-When-Then部分。一旦编写好这个FeatureSpec,就可以提交到版本管理库。当开发人员与需求、测试一起Kick Off要做的Story时,就可以根据这个FeatureSpec进行,然后,要求开发人员在完成Story的实现前,与测试结对完成它的测试实现代码。

由于ScalaTest还提供了Tag等功能,我们还可以通过对测试提取基类或者Trait有效地对这些测试进行重用,保证测试代码的可维护性。由于只需要维护一个scala,成本会降低许多,也不需要在业务场景和测试支持代码之间跳转,降低维护的难度。唯一的缺点是它天然不支持Living Document。但是我们发现这些自然语言描述实则都集中在FeatureSpec提供的方法中,我们完全可以自行开发工具或插件,完成对场景描述以及步骤的提取,生成我们需要的文档。

目前,我的同事杨云已经将ScalaTest作为编写验收测试的工具引入到项目中。受他启发,在我当前的项目中也选择使用了ScalaTest作为验收测试的框架。考虑到IDE支持尤其是重构等方面的工具支持,以及构建中对测试运行、测试覆盖率检查等的支持,目前我并没有考虑在单元测试和集成测试中使用ScalaTest。之所以如此,还是源于对成本与收益的考量。

说明:文章的代码片段全部来自ScalaTest官方网站。

相关 [scalatest 测试] 推荐:

ScalaTest的测试风格

- - 简单文本
ScalaTest几乎已经成为Scala语言默认的测试框架,而在JVM平台下,无论是否使用Scala进行开发,我认为仍有尝试ScalaTest的必要. 这主要源于它提供了多种表达力超强的测试风格,能够满足各种层次的需求包括单元测试、BDD、验收测试、数据驱动测试. 正如ScalaTest的创建者Bill Venners所说:.

测试

- 香姜 - 韩寒
测试......>>点击查看新浪博客原文.

Android单元测试与模拟测试

- - 神刀安全网
考虑可读性,对于方法名使用表达能力强的方法名,对于测试范式可以考虑使用一种规范, 如 RSpec-style. 不要使用逻辑流关键字(If/ese、for、do/while、switch/case),在一个测试方法中,如果需要有这些,拆分到单独的每个测试方法里. 测试真正需要测试的内容,需要覆盖的情况,一般情况只考虑验证输出(如某操作后,显示什么,值是什么).

免费测试VPN

- 勇 - iGFW
lusovps目前提供免费15天的PPTP VPN试用服务,. 申请地址:https://cart.lusovps.com/cart.php?a=add&pid=13. WHMCS注册系统,可以参考 http://igfw.tk/archives/3727. 注册后无需审核,立刻激活,帐号信息会发至邮箱.

HTTP负载测试

- - 博客 - 伯乐在线
英文原文: ON HTTP LOAD TESTING 来源: oschina. 有很多人在谈论HTTP服务器软件的性能测试,也许是因为现在有太多的服务器选择. 这很好,但是我看到有人很多基本相同的问题,使得测试结果的推论值得怀疑. 在日常工作中花费了很多时间在高性能代理缓存和源站性能测试方面之后,这里有我认为比较重要的一些方面来分享.

Android单元测试

- - CSDN博客推荐文章
    单元测试不管对于初学编程还是已经工作了很久的开发者来说,都不乐意花时间去写认为没用的代码进行测试,只要交给测试人员就行了,虽然这样也能把软件改出来,但也许你要花上几倍的时间去修改问题,如果在开发的过程中花点时间去写单元测试代码,把尽可能出问题的地方都测试一遍,把问题扼杀在最开始的地方,这样你就不必为后来找问题出处而烦恼.

mongodb性能测试

- - 数据库 - ITeye博客
1) Mongodb的非安全插入方式,在一开始插入性能是非常高的,但是在达到了两千万条数据之后性能骤减,这个时候恰巧是服务器24G内存基本占满的时候(随着测试的进行mongodb不断占据内存,一直到操作系统的内存全部占满),也就是说Mongodb的内存映射方式,使得数据全部在内存中的时候速度飞快,当部分数据需要换出到磁盘上之后,性能下降很厉害.

Android集成测试

- - 百度质量部 | 软件测试 | 测试技术 | 百度测试
  Android集成测试主要是在单元测试的基础上测试接口访问或者异步任务是否正确,在. 移动凤巢系统中,大概有30+个接口需要测试,他们都遵循一个特定的访问模式:前台的. Activity获取到触发事件后,将它传给这些接口,这些接口都是AsyncTask的实现——即后台. 异步线程执行某个任务(一般是发送http请求到后端服务或者执行存取数据库等耗时操作),.

测试touch事件

- - Kejun's Blog
进入触屏时代意味一切要对触屏友好. 今天仅仅测试了ios6,其它版本包括android还不清楚差别有多大. 看了PPK的touch兼容表(http://www.quirksmode.org/mobile/tableTouch.html),深感刚准备告别ie6,又迎来了一个新的混乱时代,苦逼的前端工程师们永远摆脱不了兼容的魔咒.

impala测试报告

- - 开源软件 - ITeye博客
10.200.187.86 cslave1 4核 3G. 10.200.187.87 cslave2 2核 4G. 10.200.187.88 cslave3 2核 4G. 10.200.187.89 cslave4 2核 6G. 1.在内存够用并且是简单sql条件下,impala相比hive执行效率高很多,简单的sql在百万级别数据中运行,耗时几秒甚至不用一秒.