【问题标题】:Mocking scala object模拟 scala 对象
【发布时间】:2011-04-04 07:49:55
【问题描述】:

我正在使用 mockito 并试图模拟一个 scala 对象。

object Sample { }
//test
class SomeTest extends Specification with ScalaTest with Mockito {
    "mocking should succeed" in {
        val mockedSample = mock[Sample]
     }
}

这给了我两个编译错误。

error: Not found type Sample
error: could not find implicit value for parameter m:
scala.reflect.ClassManifest[<error>]

如果我将 Sample 从对象更改为类,它就可以工作。 是否可以用 mockito 模拟 scala 对象?如果是怎么办?

【问题讨论】:

    标签: scala object mocking mockito specs


    【解决方案1】:

    正如所写,您的 Sample 是一个纯单例。它的类型是它自己的,并且该类型只有一个成员,句号。 Scala objects 可以扩展另一个类(可能是抽象的,如果它提供了使其具体化的必要定义)和特征。这样做会给它一个包含这些祖先的类型标识。

    我不知道 Mockito 真正在做什么,但在我看来,你所要求的与 Scala object 是完全不相符的。

    【讨论】:

    • 在这里绝对同意。您也许可以尝试 mock[Sample.type],但我怀疑它在实践中是否可行。我建议让 Sample 扩展一些接口特征并以这种方式模拟它。最大的问题是,如果你想注入你的 mock 来代替单例 Sample,你将不得不做一些好的、邪恶的、有趣的反射魔法。如果您有兴趣,我们可以发布。
    • 前几天我正在查看 Mockito 源代码以回答一个相关问题(由于某种原因我现在找不到),我似乎记得看到过一个“模拟”生成器返回一个特定的值,而不是尝试生成替代/变体。
    • 有没有办法用 Powermock 或类似的方法来做到这一点?如果我在伴随对象上有一个(有效的全局)方法,那么想要模拟它的行为似乎是合理的;这当然是红宝石世界的常见模式。
    • jsuereth,我知道这是一篇旧帖子,但我想知道将模拟注入单例对象的方法。谢谢。
    【解决方案2】:

    请记住,如果将 object方法 提升为函数,您可以模拟它们。

    case class Person(name: String)
    object Person {
      def listToJson(lp: List[Person]) = "some actual implementation"
    }
    
    class ClassUnderTest(listToJson: (List[Person]) => String = Person.listToJson(_)) {
      def testIt(lp: List[Person]) = listToJson(lp)
    }
    
    import org.specs._
    import org.specs.mock.Mockito
    import org.mockito.Matchers._  
    
    class ASpec extends Specification with Mockito {
      "a thing" should {
        "do whatever" in {
          val m = mock[(List[Person]) => String]
          val subject = new ClassUnderTest(m)
          m(Nil) returns "mocked!"
          subject.testIt(Nil) must_== "mocked! (this will fail on purpose)"
        }
      }
    }
    

    在这里,我不是在嘲笑对象 Person,而是在嘲笑对象上的方法(这可能是 OP 的意图)。

    测试结果显示模拟作品:

    [info] == ASpec ==
    [error] x a thing should
    [error]   x do whatever
    [error]     'mocked![]' is not equal to 'mocked![ (this will fail on purpose)]' (ASpec.scala:21)
    [info] == ASpec ==
    

    同时,ClassUnderTest 的生产时间使用只是 new ClassUnderTest,因为注入的函数是默认参数。

    【讨论】:

      【解决方案3】:

      从 mockito-scala 的 1.16.0 版开始,可以模拟 Scala objects,您可以查看文档 here,但这是它的外观示例。

      object FooObject {
       def simpleMethod: String = "not mocked!"
      }
      
      "mock" should {
       "stub an object method" in {
         FooObject.simpleMethod shouldBe "not mocked!"
      
         withObjectMocked[FooObject.type] {
           FooObject.simpleMethod returns "mocked!"
           //or
           when(FooObject.simpleMethod) thenReturn "mocked!"
      
           FooObject.simpleMethod shouldBe "mocked!"
         }
      
         FooObject.simpleMethod shouldBe "not mocked!"
       }
      }
      

      【讨论】:

        【解决方案4】:

        我最近发布了ScalaMock,这是一个用于 Scala 的模拟库,除其他外,它可以模拟单例(和伴侣)对象。

        【讨论】:

        • 在提供的页面上,在标题为“未来计划”的部分下声明了对单例和伴随对象的支持。框架目前是否支持这些功能?
        • @Zotov,似乎只有使用 2.9 编译器插件的 ScalaMock2 才能支持模拟对象,如tutorial 中所述。 ScalaMock3 不需要编译器插件,因为它依赖于 Scala 2.10 宏,但它还不支持 ScalaMock2 的所有功能,如blog post 中所述。因此 2.10 不支持模拟对象):据我所知,这似乎仍然是项目的当前状态。
        • ScalaMock 的当前文档直接与此答案相矛盾。请参阅“我可以模拟对象吗?” FAQ 中的部分。
        • 诺亚对我来说似乎是正确的。这个答案是否有效/正确(现在)?
        猜你喜欢
        • 1970-01-01
        • 2017-09-14
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-24
        • 1970-01-01
        • 1970-01-01
        • 2023-01-21
        相关资源
        最近更新 更多