讀古今文學網 > Java程序員修煉之道 > 11.3 ScalaTest >

11.3 ScalaTest

如果你還記得,我們在7.4節說過TDD是動態語言的理想用例。實際上,Scala先進的類型推斷讓它在做測試上同樣也有很多優勢,儘管它是靜態類型系統,還是經常會讓人覺得它是動態語言。

Scala中的主測試框架是ScalaTest。它為做各種測試提供了一些極其實用的特質和類——從JUnit風格的單元測試到全面的集成和驗收測試。我們來看一個ScalaTest的實戰例子。

代碼清單11-21用ScalaTest重寫了11.4節中的代碼,並且加了一個新的sellTicket方法測試fiftyDiscountTickets

代碼清單11-21 ScalaTest風格的JUnit測試

import java.math.BigDecimal
import java.lang.IllegalArgumentException
import org.scalatest.junit.JUnitSuite
import org.scalatest.junit.ShouldMatchersForJUnit
import org.junit.Test
import org.junit.Before
import org.junit.Assert._

class RevenueTest extends JUnitSuite with ShouldMatchersForJUnit {

  var venueRevenue: TicketRevenue = _

  @Before def initialize {
    venueRevenue = new TicketRevenue
  }

  @Test def zeroSalesEqualsZeroRevenue {
    assertEquals(BigDecimal.ZERO, venueRevenue estimateTotalRevenue 0);
  }

  @Test def failIfTooManyOrTooFewTicketsAreSold {
    evaluating { venueRevenue.estimateTotalRevenue(-1) }
  ➥ should produce [IllegalArgumentException]  //預期的異常
    evaluating { venueRevenue.estimateTotalRevenue(101) }
  ➥ should produce [IllegalArgumentException]
    }

  @Test def tenTicketsSoldIsThreeHundredInRevenue {
    val expected = new BigDecimal("300");
    assert(expected == venueRevenue.estimateTotalRevenue(10));
  }

  @Test def fiftyDiscountTickets {
    for (i <- 1 to 50)
➥ venueRevenue.sellTicket(new Ticket)
    for (i <- 1 to 50)
➥ venueRevenue.sellTicket(new Ticket(new StubPrice,
➥ new BigDecimal(0.9)))
    assert(1950.0 ==
➥ venueRevenue.getRevenue.doubleValue);//Scala風格的斷言
  }
}
  

我們還沒講過Scala如何處理註解。它們看起來跟Java註解一樣。這沒什麼好說的。你的測試也是放在擴展了JUnitSuit的類中,這就是說ScalaTest會把這個類當做它能運行的東西。

你可以在命令行中用本地ScalaTest運行器輕鬆運行ScalaTest:

ariel:scalatest boxcat$ scala -cp /Users/boxcat/projects/tickets.jar:/Users/
      boxcat/projects/wgjd/code/lib/scalatest-1.6.1.jar:/Users/boxcat/
      projects/wgjd/code/lib/junit-4.8.2.jar org.scalatest.tools.Runner -o -s
      com.java7developer.chapter11.scalatest.RevenueTest
  

在這條命令中,所測試的Java類放在tickets.jar文件中,所以要把它跟ScalaTest和JUnit文件一起放在類路徑中。

這條命令用-s選項指定了要運行的測試集(省略-s選項會運行所有測試集中的所有測試)。-o選項把測試輸出發送到標準輸出中(用-e把測試結果輸出到標準錯誤流中)。ScalaTest參照這個配置輸出報道途徑(包括其他途徑,比如圖形化界面)。前面的例子產生的輸出如下所示:

Run starting. Expected test count is: 4
RevenueTest:
- zeroSalesEqualsZeroRevenue
- failIfTooManyOrTooFewTicketsAreSold
- tenTicketsSoldIsThreeHundredInRevenue
- fiftyDiscountTickets
Run completed in 820 milliseconds.
Total number of tests run: 4
Suites: completed 1, aborted 0
Tests: succeeded 4, failed 0, ignored 0, pending 0
All tests passed.
  

這些測試已經被編譯進了一個類文件中。只要類路徑中有JUnit和ScalaTest兩者的JAR,就可以用scala運行這些測試,而不用在JUnit運行器中。

ariel:scalatest boxcat$ scala -cp /Users/boxcat/projects/tickets.jar:/Users/
boxcat/projects/wgjd/code/lib/scalatest-1.6.1.jar:/Users/boxcat/
projects/wgjd/code/lib/junit-4.8.2.jar org.junit.runner.JUnitCore
com.java7developer.chapter11.scalatest.RevenueTest
JUnit version 4.8.2
...
Time: 0.096
OK (4 tests)
  

當然,輸出會稍有不同,因為執行測試用的是不同的工具(JUnit運行器)。

注意 在用Maven構建第12章的java7developer項目時,我們會用這個JUnit運行器。


用ScalaTest測試Scala代碼

我們在這一節主要討論用ScalaTest測試Java代碼。但如果你用Scala作為項目中的主要編程語言會怎麼樣?

人們通常認為Scala是穩定層語言,所以如果你在使用Scala代碼,應該也可以像測試Java代碼那樣測試Scala代碼庫。所以用ScalaTest代替JUnit是使用TDD方式的不二之選。

快速瞭解ScalaTest後,我們對TDD的討論就結束了。