如何测试非公开方法?

时间:2015-07-30 21:57:22

标签: scala unit-testing junit scalatest

我正在学习Scala并写了Email类看起来像:

class Email(emailConfigName: String) {
  private val emailConfig = ConfigFactory.load(emailConfigName) getConfig ("email")

  def notifySupportForTenant(symbolicName: String) {
    val emailMessage: Message = constructEmailMessage(symbolicName)
    Transport.send(emailMessage)
  }

  def constructEmailMessage(symbolicName: String): Message = {
    val message = createMessage(emailConfig getString ("shn.mail.smtp.host"))
    message setFrom (new InternetAddress(emailConfig getString ("shn.mail.from")))
    // todo: should come from API (sent by client)
    message setSentDate (new Date())
    message setSubject (emailConfig getString ("shn.mail.subject") replace("TENANT_ID", symbolicName))
    message setContent(emailConfig getString ("shn.mail.body"), "text/html")
    message.setRecipients(Message.RecipientType.TO, getMessageRecipients(emailConfig getString ("shn.mail.recipient")))
    message
  }

  private def createMessage(smtpHost: String): Message = {
    val properties = new Properties()
    properties put("mail.smtp.host", smtpHost)
    val session = Session.getDefaultInstance(properties, null)
    return new MimeMessage(session)
  }

  private def getMessageRecipients(recipient: String): Array[Address] = {
    // had to do the asInstanceOf[...] call here to make scala happy
    val addressArray = buildInternetAddressArray(recipient).asInstanceOf[Array[Address]]
    if ((addressArray != null) && (addressArray.length > 0)) addressArray
    else
      throw new IllegalArgumentException("no recipients found to send email")
  }

  private def buildInternetAddressArray(address: String): Array[InternetAddress] = {
    // could test for a null or blank String but I'm letting parse just throw an exception
    return InternetAddress.parse(address)
  }
}

我想测试这个类的公共API,notifySupportForTenant,但这不适合单元测试,因为它还会调用Transport.send(emailMessage)来发送电子邮件。

我有兴趣测试邮件是否构造正确。这意味着我需要测试constructEmailMessage

为了测试这个,我不得不将这个public作为公共接口公开,我不喜欢。我该怎么办?

2 个答案:

答案 0 :(得分:6)

在传统的OO中,编程方法通常是私有的,因此它们不能被外部调用并破坏实例的状态。一旦你的方法真的是一个没有副作用的函数(如constructEmailMessage所示),那么就没有理由将其设为私有。

由于您的目的是学习scala,我建议您尽可能采用对不可变数据进行操作的函数式样,因为它减轻了OO编程有利于受保护封装的许多原因。

答案 1 :(得分:0)

您可以使用PowerMock库!

import org.powermock.reflect.Whitebox

val email = new Email("lalala@mail.com")
val expected = new Message(...)
val smtpHost = "127.0.0.1"

val actual = Whitebox.invokeMethod(email, "createMessage", smtpHost).asInstanceOf[Message]

assert(actual = expected)

此库也有助于模拟私有方法,但如果您不需要为您执行任务,则可以使用此post中提到的反射。