模拟部分(异常抛出)功能

时间:2014-07-08 15:02:45

标签: scala unit-testing mockito specs2

我正在使用Scala中的Mockito和Specs 2编写单元测试。我有一个类Foo,其方法bar在其输入参数x的域中部分定义。如果没有为给定的输入值定义结果,则抛出FooException

public abstract class Foo {
  public abstract int bar(String x) throws FooException;
}

public class FooException extends Exception {}

现在我正在尝试使用Mockito创建一个模拟器。我希望指定该栏仅返回xy的结果,否则会抛出异常:

import org.specs2.mutable.Specification
import org.specs2.mock.Mockito
import org.mockito.Matchers._

class FooTest extends Specification with Mockito {

   val foo = mock[Foo]
   foo.bar("x") returns 1
   foo.bar("y") returns 2
   foo.bar(anyString) throws mock[FooException]

   "Foo.bar()" should {
       "return an integer for x" in {
           foo.bar("x") must be equalTo(1)
       }

      "throw an exception for z" in {
           foo.bar("z") must throwA[FooException]
      }
   }
}

不幸的是,这个测试失败了。如何以我的测试通过的方式编写模拟?

更新

测试失败,因为在运行时抛出异常。上面的代码导致:

java.lang.NullPointerException
[error] Could not run test FooTest: java.lang.NullPointerException

如果按照其中一个答案中的建议更改顺序,我会得到以下堆栈跟踪:

[error] Could not create an instance of FooTest
[error]   caused by java.lang.Exception: Could not instantiate class FooTest: null
[error]   org.specs2.reflect.Classes$class.tryToCreateObjectEither(Classes.scala:93)
[error]   org.specs2.reflect.Classes$.tryToCreateObjectEither(Classes.scala:207)
[error]   org.specs2.specification.SpecificationStructure$$anonfun$createSpecificationEither$2.apply(BaseSpecification.scala:119)
[error]   org.specs2.specification.SpecificationStructure$$anonfun$createSpecificationEither$2.apply(BaseSpecification.scala:119)
[error]   scala.Option.getOrElse(Option.scala:120)
[error]   org.specs2.specification.SpecificationStructure$.createSpecificationEither(BaseSpecification.scala:119)
[error]   org.specs2.runner.SbtRunner.org$specs2$runner$SbtRunner$$specificationRun(SbtRunner.scala:73)
[error]   org.specs2.runner.SbtRunner$$anonfun$newTask$1$$anon$5.execute(SbtRunner.scala:59)
[error]   sbt.TestRunner.runTest$1(TestFramework.scala:84)
[error]   sbt.TestRunner.run(TestFramework.scala:94)
[error]   sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:219)
[error]   sbt.TestFramework$$anon$2$$anonfun$$init$$1$$anonfun$apply$8.apply(TestFramework.scala:219)
[error]   sbt.TestFramework$.sbt$TestFramework$$withContextLoader(TestFramework.scala:207)
[error]   sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:219)
[error]   sbt.TestFramework$$anon$2$$anonfun$$init$$1.apply(TestFramework.scala:219)
[error]   sbt.TestFunction.apply(TestFramework.scala:224)
[error]   sbt.Tests$$anonfun$7.apply(Tests.scala:196)
[error]   sbt.Tests$$anonfun$7.apply(Tests.scala:196)
[error]   sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
[error]   sbt.std.Transform$$anon$3$$anonfun$apply$2.apply(System.scala:45)
[error]   sbt.std.Transform$$anon$4.work(System.scala:64)
[error]   sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
[error]   sbt.Execute$$anonfun$submit$1$$anonfun$apply$1.apply(Execute.scala:237)
[error]   sbt.ErrorHandling$.wideConvert(ErrorHandling.scala:18)
[error]   sbt.Execute.work(Execute.scala:244)
[error]   sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
[error]   sbt.Execute$$anonfun$submit$1.apply(Execute.scala:237)
[error]   sbt.ConcurrentRestrictions$$anon$4$$anonfun$1.apply(ConcurrentRestrictions.scala:160)
[error]   sbt.CompletionService$$anon$2.call(CompletionService.scala:30)
[error]   java.util.concurrent.FutureTask.run(FutureTask.java:262)
[error]   java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:471)
[error]   java.util.concurrent.FutureTask.run(FutureTask.java:262)
[error]   java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
[error]   java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
[error]   java.lang.Thread.run(Thread.java:744)
[error]   caused by java.lang.NullPointerException

2 个答案:

答案 0 :(得分:0)

您需要更改存根的顺序。首先对通用行为进行存根(anyString),然后再添加更具体的行为。所以这样做:

val foo = mock[Foo]
foo.bar(anyString) throws mock[FooException]
foo.bar("x") returns 1
foo.bar("y") returns 2

答案 1 :(得分:-1)

您可以在模拟上设置回调:

  val foo = mock[Foo]
  foo.bar(anyString) answers (derp => {
    derp match {
      case "x" => 1
      case "y" => 2
      case _ => throw mock[FooException]
    }
  })

specs2 documentation中有更多详细信息。