首页 » Java程序员修炼之道 » Java程序员修炼之道全文在线阅读

《Java程序员修炼之道》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.BigDecimalimport java.lang.IllegalArgumentExceptionimport org.scalatest.junit.JUnitSuiteimport org.scalatest.junit.ShouldMatchersForJUnitimport org.junit.Testimport org.junit.Beforeimport 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: 4RevenueTest:- zeroSalesEqualsZeroRevenue- failIfTooManyOrTooFewTicketsAreSold- tenTicketsSoldIsThreeHundredInRevenue- fiftyDiscountTicketsRun completed in 820 milliseconds.Total number of tests run: 4Suites: completed 1, aborted 0Tests: succeeded 4, failed 0, ignored 0, pending 0All 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.JUnitCorecom.java7developer.chapter11.scalatest.RevenueTestJUnit version 4.8.2...Time: 0.096OK (4 tests)  

当然,输出会稍有不同,因为执行测试用的是不同的工具(JUnit运行器)。

注意 在用Maven构建第12章的java7developer项目时,我们会用这个JUnit运行器。


用ScalaTest测试Scala代码

我们在这一节主要讨论用ScalaTest测试Java代码。但如果你用Scala作为项目中的主要编程语言会怎么样?

人们通常认为Scala是稳定层语言,所以如果你在使用Scala代码,应该也可以像测试Java代码那样测试Scala代码库。所以用ScalaTest代替JUnit是使用TDD方式的不二之选。

快速了解ScalaTest后,我们对TDD的讨论就结束了。