在scalatest中测试方法时,是否可以模拟/存根在方法调用中实例化的对象?

时间:2018-08-09 13:20:46

标签: scala unit-testing mocking scalatest stubbing

现在,我正在为一种方法编写一个测试套件,该方法接受一个字符串,实例化数据库端点,然后使用该字符串查询端点。然后,它将获取此响应,对其进行几次转换,最后返回它。看起来大概是这样的:

method(s: String){
    dbEndpoint database = new dbEndpoint()
    DataFrame df = database.read(s)
    df.transform(...)
}

由于我已经为数据库端点编写了测试,并且确信它足够健壮,因此我只关心确保数据库查询后发生的转换逻辑正确。因此,我想对端点进行存根处理,以便使endpoint.read()返回少量数据,可以轻松验证其转换是否正确。

据我了解,无法对这个特定端点进行存根处理,因为我没有在方法范围之外引用它。我错了吗?有什么办法可以使我从外部对数据库进行存根/模拟(无需更改方法)?

2 个答案:

答案 0 :(得分:1)

警告:确实可以使用PowerMock做到这一点,尽管只能按照@ bruno-bonanno的建议,在万不得已的情况下完成此操作。

PowerMock支持使用以下三个设施来模拟硬连线的本地范围依赖性,例如dbEndpoint

  • PowerMockito.whenNew
  • @RunWith
  • @PrepareForTest

这是一个使用Scala,PowerMock,Mockito和JUnit的工作示例:

import org.scalatest.junit.AssertionsForJUnit
import org.junit.Assert._
import org.junit.Test
import org.junit.runner.RunWith
import org.powermock.api.mockito.PowerMockito
import org.powermock.core.classloader.annotations.PrepareForTest
import org.powermock.modules.junit4.PowerMockRunner
import org.mockito.Mockito._

class Hardwired {
  def f(i: Int): String = s"I am a real Hardwired instance"
}

class Foo {
  def bar(i: Int): String = {
    val localHardwiredInstance = new Hardwired()
    localHardwiredInstance.f(i)
  }
}

@RunWith(classOf[PowerMockRunner])
@PrepareForTest(Array(classOf[Foo]))
class ExampleSuite extends AssertionsForJUnit {
  @Test def mockLocalHardwiredDependency() {
    val hardwiredMock = mock(classOf[Hardwired])
    when(hardwiredMock.f(3)).thenReturn("I am a mocked Hardwired instance")
    PowerMockito.whenNew(classOf[Hardwired]).withNoArguments().thenReturn(hardwiredMock)
    val foo = new Foo
    assertEquals("I am a mocked Hardwired instance", foo.bar(3))
  }
}

build.sbt:

libraryDependencies ++= Seq(
  scalaTest % Test,
  "org.powermock" % "powermock-api-mockito" % "1.7.4" % Test,
  "org.powermock" % "powermock-core" % "1.7.4" % Test,
  "org.powermock" % "powermock-module-junit4" % "1.7.4" % Test,
  "org.mockito" % "mockito-core" % "1.10.19" % Test,
  "com.novocode" % "junit-interface" % "0.11" % Test,
),
testOptions += Tests.Argument(TestFrameworks.JUnit, "-v")

我不确定如何用ScalaTest运行它-我相信我们需要一个相应的PowerMockRunner,但是目前我找不到它。

答案 1 :(得分:1)

您可以做的就是修改代码,使其看起来像这样

exit

这样,您的调用方可以继续调用该方法而无需关心maybe_exit() { local last_retval=$? # preserve exit's behavior of defaulting to $? [[ $do_not_really_exit ]] && return # abort if flag is set (( $# )) && exit "$@" # if arguments are given, pass them through exit "$last_retval" # otherwise, use the $? we captured above } shopt -s expand_aliases # enable alias expansion (off by default in noninteractive shells) alias exit=maybe_exit # ...and alias 'exit' to 'maybe_exit' do_not_really_exit=1 # set a flag telling maybe_exit not to really exit source 'file2.sh' # source in your file which incorrectly uses 'exit' at top-level unset do_not_really_exit # clear that flag... unalias exit # disable the alias... echo 'after source' func1 ,但是在测试中,您可以创建一个模拟并将其作为第二个参数传递