第16章——单元测试
代码将总是按照被编写的行为运行—单元测试将确保它做的确实符合编写者的本意。 在开发应用程序的过程中,单元测试还有助于确保代码行为持续符合预期。
16.1 使用 JUnit
UnitTesting/UsingJUnit.scala
import java.util
import org.junit.Assert._
import org.junit.Test
class UsingJUnit {
@Test
def listAdd(): Unit = {
val list = new util.ArrayList[String]
list.add("Milk")
list.add("Sugar")
assertEquals(2, list.size)
}
}
执行命令
scalac -d classes -classpath $JUNIT_JAR:$HAMCREST_JAR UsingJUnit.scala
java -classpath $SCALALIBRARY:$JUNIT_JAR:$HAMCREST_JAR:classes \
org.junit.runner.JUnitCore UsingJUnit
运行结果
JUnit version 4.12
.
Time: 0.003
OK (1 test)
16.2 使用 ScalaTest
UnitTesting/UsingScalaTest.scala
import java.util
import org.scalatest._
class UsingScalaTest extends FlatSpec with Matchers {
trait EmptyArrayList {
val list = new util.ArrayList[String]
}
"a list" should "be empty on create" in new EmptyArrayList {
list.size should be(0)
}
"a list" should "increase in size upon add" in new EmptyArrayList {
list.add("Milk")
list.add("Sugar")
list.size should be(2)
}
}
执行命令
scalac -d classes -classpath $SCALA_TEST_JAR UsingScalaTest.scala
scala -classpath $SCALA_TEST_JAR:classes org.scalatest.run UsingScalaTest
运行结果
Run starting. Expected test count is: 2
UsingScalaTest:
a list
- should be empty on create
a list
- should increase in size upon add
Run completed in 181 milliseconds.
Total number of tests run: 2
Suites: completed 1, aborted 0
Tests: succeeded 2, failed 0, canceled 0, ignored 0, pending 0
All tests passed.
16.3 使用 Mockito
UnitTesting/WordScorerTest.scala (withoutmock)
import org.scalatest.{ FlatSpec, Matchers }
class WordScorerTest extends FlatSpec with Matchers {
def withWordScorer(test: WordScorer => Unit): Unit = {
val wordScorer = new WordScorer()
test(wordScorer)
}
"score" should "return 0 for an empty word" in {
withWordScorer { wordScorer =>
wordScorer.score("") should be(0)
}
}
"score" should "return 2 for word with two vowels" in {
withWordScorer { _.score("ai") should be(2) }
}
"score" should "return 8 for word with four consonants" in {
withWordScorer { _.score("myth") should be(8) }
}
"score" should "return 7 for word with a vowel and three consonants" in {
withWordScorer { _.score("that") should be(7) }
}
}
UnitTesting/WordScorer.scala (withoutmock)
class WordScorer() {
private val VOWELS = List('a', 'e', 'i', 'o', 'u')
def score(word: String): Int = {
(0 /: word) { (total, letter) =>
total + (if (VOWELS.contains(letter)) 1 else 2)
}
}
}
执行命令
scalac -d classes -classpath $SCALA_TEST_JAR \
WordScorer.scala WordScorerTest.scala
scala -classpath $SCALA_TEST_JAR:classes org.scalatest.run WordScorerTest
运行结果
Run starting. Expected test count is: 4
WordScorerTest:
score
- should return 0 for an empty word
score
- should return 2 for word with two vowels
score
- should return 8 for word with four consonants
score
- should return 7 for word that with a vowel and three consonants
Run completed in 181 milliseconds.
Total number of tests run: 4
Suites: completed 1, aborted 0
Tests: succeeded 4, failed 0, canceled 0, ignored 0, pending 0
All tests passed.
UnitTesting/SpellChecker.scala (withmock)
trait SpellChecker {
def isCorrect(word: String): Boolean
}
UnitTesting/WordScorerTest.scala (withmock)
import org.scalatest.{ FlatSpec, Matchers }
import org.mockito.Mockito._
import org.mockito.ArgumentMatchers.anyString
class WordScorerTest extends FlatSpec with Matchers {
def withWordScorer(test: WordScorer => Unit): Boolean = {
val spellChecker = mock(classOf[SpellChecker])
when(spellChecker.isCorrect(anyString)).thenReturn(true)
val wordScorer = new WordScorer(spellChecker)
test(wordScorer)
verify(spellChecker, times(1)).isCorrect(anyString())
}
//No change to the tests, same as in the previous version
"score" should "return 0 for an empty word" in {
withWordScorer { wordScorer =>
wordScorer.score("") should be(0)
}
}
"score" should "return 2 for word with two vowels" in {
withWordScorer { _.score("ai") should be(2) }
}
"score" should "return 8 for word with four consonants" in {
withWordScorer { _.score("myth") should be(8) }
}
"score" should "return 7 for word that with a vowel and three consonants" in {
withWordScorer { _.score("that") should be(7) }
}
}
UnitTesting/WordScorer.scala (withmock)
class WordScorer(val spellChecker: SpellChecker) {
private val VOWELS = List('a', 'e', 'i', 'o', 'u')
def score(word: String): Int = {
spellChecker.isCorrect(word)
(0 /: word) { (total, letter) =>
total + (if (VOWELS.contains(letter)) 1 else 2)
}
}
}
执行命令
scalac -d classes -classpath $SCALA_TEST_JAR:$MOCKITO_JAR \
WordScorer.scala SpellChecker.scala WordScorerTest.scala
scala -classpath $SCALA_TEST_JAR::$MOCKITO_JAR:classes \
org.scalatest.run WordScorerTest
运行结果
Run starting. Expected test count is: 4
WordScorerTest:
score
- should return 0 for an empty word
score
- should return 2 for word with two vowels
score
- should return 8 for word with four consonants
score
- should return 7 for word that with a vowel and three consonants
Run completed in 316 milliseconds.
Total number of tests run: 4
Suites: completed 1, aborted 0
Tests: succeeded 4, failed 0, canceled 0, ignored 0, pending 0
All tests passed.
UnitTesting/WordScorerTest.scala (withmock2)
"score" should "return 0 for word with incorrect spelling" in {
val spellChecker = mock(classOf[SpellChecker])
when(spellChecker.isCorrect(anyString)).thenReturn(false)
val wordScorer = new WordScorer(spellChecker)
wordScorer.score("aoe") should be(0)
verify(spellChecker, times(1)).isCorrect(anyString())
}
UnitTesting/WordScorer.scala (withmock2)
def score(word: String): Int = {
if (spellChecker.isCorrect(word))
(0 /: word) { (total, letter) =>
total + (if (VOWELS.contains(letter)) 1 else 2)
} else
0
}
运行结果
Run starting. Expected test count is: 5
WordScorerTest:
score
- should return 0 for an empty word
score
- should return 2 for word with two vowels
score
- should return 8 for word with four consonants
score
- should return 7 for word that with a vowel and three consonants
score
- should return 0 for word with incorrect spelling
Run completed in 208 milliseconds.
Total number of tests run: 5
Suites: completed 1, aborted 0
Tests: succeeded 5, failed 0, canceled 0, ignored 0, pending 0
All tests passed.
1.0.0