如何为使用 Map 集合的模式匹配方法编写 ScalaTest

How to write a ScalaTest for a pattern matching method that uses a Map collection

我正在尝试为以下 Scala 对象编写我的第一组 ScalaTest 测试,该对象将 24 小时格式的时间(00:00 到 24:00)转换为文字时间(八点钟之前中午,中午前八点半,中午前九点一刻)。我正在寻找如何为 hourFmt、minutesFmt 和 Fmt 编写测试的起点,这些测试使用模式匹配和 Map 集合到 return 小时和分钟的整数值的适当单词。

我已经阅读了大部分 ScalaTest 用户指南文档,但找不到任何关于模式匹配方法或映射集合的文档。我只是在寻找社区知道的起点或示例,因为以下将是我第一次编写单元测试。

我在下面附上了我的代码,以阐明我所说的三种方法。

object TimeAsWords extends App {
  def parseTime(hhmm: String): (Int, Int) = {
    """^([01]\d|2[0-4]):([0-5]\d)$""".r.findAllIn(hhmm).matchData foreach {
      md => return (md.group(1).toInt, md.group(2).toInt)
    }
    throw new IllegalArgumentException("Input string doesn't match required format: 00:00 - 24:00")
  }

  def formatTime(hhmm: (Int, Int)): String = {
    val englishNum = Map(
      1 -> "one", 2 -> "two", 3 -> "three", 4 -> "four", 5 -> "five",
      6 -> "six", 7 -> "seven", 8 -> "eight", 9 -> "nine", 10 -> "ten",
      11 -> "eleven", 12 -> "twelve", 13 -> "thirteen", 14 -> "fourteen",
      16 -> "sixteen", 17 -> "seventeen", 18 -> "eighteen", 19 -> "nineteen",
      20 -> "twenty", 21 -> "twenty-one", 22 -> "twenty-two",
      23 -> "twenty-three", 24 -> "twenty-four", 25 -> "twenty-five",
      26 -> "twenty-six", 27 -> "twenty-seven", 28 -> "twenty-eight",
      29 -> "twenty-nine"
    )

    def hourFmt(h: Int): String = h match {
      case 0 | 24      => "midnight"
      case 12          => "noon"
      case _ if h < 12 => englishNum(h) + " o'clock before midday"
      case _           => englishNum(h - 12) + " o'clock after midday"
    }

    def minuteFmt(m: Int): String = "%s %s".format(
      englishNum(m),
      if (m == 1) "minute" else "minutes"
    )

    def fmt(m: Int): (Int => String) = m match {
      case  0          => hourFmt
      case 15          => "quarter past " + hourFmt(_)
      case 30          => "half past " + hourFmt(_)
      case 45          => h => "quarter to " + hourFmt(h + 1)
      case _ if m < 30 => h => "%s past %s".format(minuteFmt(m), hourFmt(h))
      case _           => h => "%s to %s".format(minuteFmt(60 - m), hourFmt(h + 1))
    }

    val (hh, mm) = hhmm
    fmt(mm)(hh).capitalize
  }

  try {
    println(formatTime(parseTime(args(0))))
  } catch {
    case e: IllegalArgumentException => System.err.println(e.getMessage)
      System.exit(1)
  }
}

我发布了我自己的问题的答案,但我想找到一种更好的方法来为使用依赖于其他两个函数 hourFmt 和 minutesFmt 的模式匹配的函数 fmt 编写单元测试。

我目前编写的 ScalaTest:

package time

import TimeAsWords._
import org.scalatest.FunSuite

/**
  * Created by PeterW on 6/18/2017.
  */
class TimeAsWordsTest extends FunSuite {
  test("testParseTime - 00:00") {
    assert(parseTime("00:00") == (0,0))
  }
  test("testParseTime - IllegalArgumentException") {
    val thrown = intercept[Exception] {
      parseTime("25:00")
    }
    assert(thrown.getMessage == "Input string doesn't match required format: 00:00 - 24:00")
  }
  test("testFormatTime - Midnight") {
    assert(formatTime((0,0)) == "Midnight")
  }
  test("testFormatTime - Noon") {
    assert(formatTime((12,0)) == "Noon")
  }
  test("testFormatTime - o'clock before midday") {
    assert(formatTime((8,0)) == "Eight o'clock before midday")
  }
  test("testFormatTime - o'clock after midday") {
    assert(formatTime((13,0)) == "One o'clock after midday")
  }
  test("testFormatTime - Quater past") {
    assert(formatTime((13,15)) == "Quarter past one after midday")
  }
  test("testFormatTime - Half past") {
    assert(formatTime((13,30)) == "Half past one after midday")
  }
  test("testFormatTime - Quarter to") {
    assert(formatTime((13,45)) == "Quarter to two after midday")
  }
  test("testFormatTime - Minutes past hour") {
    assert(formatTime((13,25)) == "Twenty-five minutes past one after midday")
  }
  test("testFormatTime - Minutes to hour") {
    assert(formatTime((13,35)) == "Twenty-five minutes to two after midday")
  }
  test("testFormatTime - Minute singular") {
    assert(formatTime((13,1)) == "One minute past one after midday")
  }
  test("testFormatTime - Minutes plural") {
    assert(formatTime((13,2)) == "Two minutes past one after midday")
  }
}