当前位置: 首页 > 工具软件 > ScalaTest > 使用案例 >

ScalaTest——测试风格

唐珂
2023-12-01

建议使用 FlatSpec单元和集成测试以及 FeatureSpec验收测试。将FlatSpec作为默认选择,因为它与大多数开发人员熟悉的XUnit测试类似

2.1 FunSuite

FunSuite可以轻松编写描述性测试名称,自然地编写集中测试,并生成类似规范的输出

import org.scalatest.FunSuite
//ScalaTest提供了名为FunSuite的特质重载了execute方法从而可以用函数值的方式,而不是方法定义测试
class SetSuite extends FunSuite {
/**
  * test后面圆括号()内为测试名称,可以使用任何字符串,不需要传统的驼峰形式命名。
  * !!!!!!!但是名称需要唯一!!!!!!!!!!!
  * 圆括号后面的大括号{}之内定义的为测试代码。被作为传名参数传递给test函数,由test登记备用
  */
  test("An empty Set should have size 0") {
    assert(Set.empty.size == 0)
  }
  test("Invoking head on an empty Set should produce NoSuchElementException") {
    assertThrows[NoSuchElementException] {
    //intercept[NoSuchElementException] {  旧版本使用,现在仍可用
      Set.empty.head
    }
  }
}

如果需要测试异常的抛出情况

import java.io.IOException
import org.scalatest.FunSuite

class TestUtilSuit extends FunSuite{
  test("get execption"){
    intercept[IOException]{
      val a = 1/0
    }
  }
}

这里期望抛出IOExexeption,但实际抛出了ArithmeticException异常。所以控制台就会报出错误信息如下:
Expected exception java.io.IOException to be thrown, but java.lang.ArithmeticException was thrown.ScalaTestFailureLocation: TestUtilSuit$$anonfun$2 at (ForTest2.scala:21)
org.scalatest.exceptions.TestFailedException: 
Expected exception java.io.IOException to be thrown, but java.lang.ArithmeticException was thrown.at
org.scalatest.Assertions$class.newAssertionFailedException(Assertions.scala:496)at org.scalatest.FunSuite.newAssertionFailedException(FunSuite.scala:1555)

提示一下,如果大括号之间的代码被一个参数指定的异常类的实例突然中断,intercept 将返回捕获的异常,以便于之后进行检查。另一方面,如果代码没有抛出异常,或抛出了不同的异常,intercept将抛出 AssertionError,并且将在失败报告中得到错误消息。
2.2 FlatSpec

FlatSpec结构像xUnit一样扁平,简单和熟悉,但测试名称必须以规范样式编写:“X should Y”,“A must B, “ 等等。

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 {
    assertThrows[NoSuchElementException] {
    //intercept[NoSuchElementException] {  旧版本使用,现在仍可用
      Set.empty.head
    }
  }
}
2.3 FunSpec

FunSpec嵌套和温和的结构化文本指南(带describeit)为编写规范式测试提供了极好的通用选择。

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") {
        assertThrows[NoSuchElementException] {
        //intercept[NoSuchElementException] {  旧版本使用,现在仍可用
          Set.empty.head
        }
      }
    }
  }
}
2.4 WordSpec

WordSpec对于如何编写文本的要求非常规范,因此非常适合希望在其规范文本上强制执行高度管理的团队。

import org.scalatest.WordSpec
 
class SetSpec extends WordSpec {
  "A Set" when {
    "empty" should {
      "have size 0" in {
        assert(Set.empty.size == 0)
      }

      "produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
  }
}
2.5 FreeSpec

因为它给出了如何编写规范文本的绝对自由(并且没有指导),FreeSpec对于有BDD经验并且能够就如何构建规范文本达成一致的团队来说是一个很好的选择。

import org.scalatest.FreeSpec

class SetSpec extends FreeSpec {
  "A Set" - {
    "when empty" - {
      "should have size 0" in {
        assert(Set.empty.size == 0)
      }

      "should produce NoSuchElementException when head is invoked" in {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
  }
}
2.6 PropSpec

PropSpec非常适合那些想要在财产检查方面专门编写测试的团队; 当选择不同的样式特征作为主要单元测试样式时,也是编写偶尔测试矩阵的好选择。

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 }
    }
  }
}
2.7 FeatureSpec

FeatureSpec主要用于验收测试,包括促进程序员与非程序员一起工作以定义验收要求的过程。

import org.scalatest._

class TVSet {
  private var on: Boolean = false
  def isOn: Boolean = on
  def pressPowerButton() {
    on = !on
  }
}

class TVSetSpec extends FeatureSpec with GivenWhenThen {

  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 presses power button when TV is off") {

      Given("a TV set that is switched off")
      val tv = new TVSet
      assert(!tv.isOn)

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

      Then("the TV should switch on")
      assert(tv.isOn)
    }

    scenario("User presses power button when TV is on") {

      Given("a TV set that is switched on")
      val tv = new TVSet
      tv.pressPowerButton()
      assert(tv.isOn)

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

      Then("the TV should switch off")
      assert(!tv.isOn)
    }
  }
}
2.8 RefSpec (JVM only)

RefSpec允许您将测试定义为方法,与将测试表示为函数的样式类相比,每个测试保存一个函数文字。更少的函数文字转换为更快的编译时间和更少的生成的类文件,这可以帮助最小化构建时间。因此,Spec在构建时间受到关注的大型项目中以及通过静态代码生成器以编程方式生成大量测试时,使用可能是一个不错的选择。

import org.scalatest.refspec.RefSpec

class SetSpec extends RefSpec {
  object `A Set` {
    object `when empty` {
      def `should have size 0` {
        assert(Set.empty.size == 0)
      }

      def `should produce NoSuchElementException when head is invoked` {
        assertThrows[NoSuchElementException] {
          Set.empty.head
        }
      }
    }
  }
}

 类似资料: