如何对应用于输入的验证规则进行单元测试

时间:2018-08-05 14:17:21

标签: scala unit-testing

代码在Scala中,但问题也与其他语言有关。

假设我们有一些课程:

class SomeClass(inputString: String) {
  private val name: String = readName()
  private val method: Method = readMethod()

  def sayHello(): String = { 
    if (method == USE_XXX) {
      s"Hello, my name is $name"
    } else "I don't know"
  }

  private def readName(): String = {
    val nameRegex ="""(?mi)^NAME\s*:\s*(.*)$""".r
    val name = for (m <- nameRegex.findFirstMatchIn(inputString)) yield m.group(1)
    name.getOrElse(throw new CustomException("No name in input"))
  }

  private def readMethod(): Method = {
    val methodRegex = """(?mi)^METHOD\s*:\s*(.*)$""".r
    val method = for (m <- methodRegex.findFirstMatchIn(inputString)) yield m.group(1)
    method.getOrElse("") match {
      case "XXX" => USE_XXX
      case _ => UNKNOWN
    }
  }

  sealed trait Method
  case object USE_XXX extends Method
  case object UNKOWN extends Method
}

如您所见,它的公共接口只是方法sayHello()。 但是,当实例化该类的对象时,readName可能会引发异常,因为需要name字段。

问题是,如何对此类进行单元测试。我想编写单元测试,以针对给定功能(隔离)的特定输入测试两个私有功能,例如:

tests for readName() with texts:
  1) "NAME: ok"
  2) "NAME: first occurance\nNAME: second occurance"
  3) "name: keyword lowercase"
  4) "NAME :  whitespaces around semicolon"
  5) AssertThrows[CustomException](SomeClass("NONAME"))

test for readMethod() with texts:
  1) "NO METHOD KEYWORD" -> should have be UNKOWN
  2) "METHOD: XXX"
  3) "method: xxx"
etc.

问题在于,用于测试readMethod()的输入文本还应包含NAME:关键字,以防止引发异常。如果在每个测试中还存在其他字段和验证规则,则必须使用该字段和输入来满足所有验证规则,但要满足所有验证规则,因此很难维护测试服。

如何处理这样的问题?

最简单的方法是将异常抛出移至sayHello()方法,但这有一个缺点-在系统的其他部分执行了一些昂贵的计算后,可能会调用该方法,但是它应该警告用户尽早(“尊敬的用户,您提供的数据有误,名称丢失。您真的要继续吗?”-或类似的东西)。

1 个答案:

答案 0 :(得分:0)

此类的外部接口是构造函数(new SomeClass(string))和sayHello方法。这是在任何单元测试中都应该测试的行为,并且这样做非常简单。

readNamereadMethod是内部实现功能,可以用其他方式实现(例如(name, method) = readNameAndMethod())。因此,测试readNamereadMethod是没有意义的,因为它们是实现的一部分。

如果要将readNamereadMethod作为单独的功能进行测试,则可以将它们作为公共方法放在单独的可测试对象上。然后它们是一个公共接口,并且可以拥有自己的单元测试套件。