【问题标题】:how to use mocking in unit testing in scala如何在scala的单元测试中使用模拟
【发布时间】:2015-04-09 12:33:26
【问题描述】:

嗨,我是单元测试的新手,我想使用模拟对象对其进行测试。我想测试数据是否成功存储在 mongoDB 中 这是我的代码

package models.RegularUserModels
import models.UserModels.UserStatus._
// User will give information to Signup  

    class DirectUser() extends RegularUser{
      override val uuid = "direct123"
       override val firstName ="sara"
       lastName = "waheed"
       email = "user@example.com"
       secondryEmail  =Some("user2@example.com") 

        userStatus =ACTIVE

     }

这是我要测试的类

package models.RegularUserModels

import com.mongodb.casbah.Imports._
import com.mongodb.QueryBuilder

class directUserStore {
  def write(directuser:DirectUser) ={
    val serverAddress=new ServerAddress("Localhost",27017)
    val client= MongoClient(serverAddress)

   val CourseDB = client("arteciatedb")//get database Name
    val collection = CourseDB("directUser")//get collection Name

    collection.drop()

        collection.insert(new BasicDBObject("_id",directuser.uuid)
                        .append("Email",directuser.email)
                        .append("SecondryEmail",directuser.secondryEmail)
                        .append("FirstName",directuser.firstName)
                        .append("LastName",directuser.lastName)
                        .append("UserStatus",directuser.userStatus.toString())
                        )

  }

}

制作一个scala对象来检查代码是否正常工作

object Test extends App{

val directUser= new DirectUser() 

/////////////////////////DirectUser mongo DB//////////////////////////
//insert in mongoDB
val directUserStore= new directUserStore
directUserStore.write(directUser)
}

现在我想对 DirectUserStore.scala 类进行测试,所以在 sbt 的 src/test 目录中我创建了这个类

package testingModels.RegularUserModels
import models._
import models.RegularUserModels._
import org.scalatest.Matchers._
import org.scalatest.MustMatchers._
import org.scalatest.Spec
import org.scalatest.FunSpec
import org.easymock.EasyMock._
import org.scalatest.mock.EasyMockSugar

class DirectUserStoreTest extends FunSpec with org.scalatest.MustMatchers with EasyMockSugar {
    describe("A DirectUserStoreTest"){
      it("should use easy mock to mock out the DAO classes")
      {
        val DirectUserMock= createMock(classOf[directUserStore])
       /* val directUserStore= new directUserStore
        //replay, more like rewind
        replay(DirectUserMock)
        //make the call
        directUserStore.write(DirectUserMock)
        //verify that the calls expected were made
         verify(DirectUserMock)
*/      val directUser = new DirectUser 

        expecting{
        DirectUserMock.write(directUser)  
        }
        whenExecuting(DirectUserMock) {
        val directUserStore= new directUserStore
        directUserStore.write(directUser)

          }
      }
    }
}    

但是当我在 sbt 中输入 test 时,我的测试失败了

[info] DirectUserStoreTest:
[info] A DirectUserStoreTest
[info] - should use easy mock to mock out the DAO classes *** FAILED ***
[info]   java.lang.IllegalStateException: missing behavior definition for the preceding method call:
[info] directUserStore.write(models.RegularUserModels.DirectUser@1fe2433b)
[info] Usage is: expect(a.foo()).andXXX()
[info]   at org.easymock.internal.MocksControl.replay(MocksControl.java:173)
[info]   at org.easymock.EasyMock.replay(EasyMock.java:2074)
[info]   at org.scalatest.mock.EasyMockSugar$$anonfun$whenExecuting$2.apply(EasyMockSugar.scala:421)
[info]   at org.scalatest.mock.EasyMockSugar$$anonfun$whenExecuting$2.apply(EasyMockSugar.scala:420)
[info]   at scala.collection.IndexedSeqOptimized$class.foreach(IndexedSeqOptimized.scala:33)
[info]   at scala.collection.mutable.WrappedArray.foreach(WrappedArray.scala:35)
[info]   at org.scalatest.mock.EasyMockSugar$class.whenExecuting(EasyMockSugar.scala:420)
[info]   at testingModels.RegularUserModels.DirectUserStoreTest.whenExecuting(DirectUserStoreTest.scala:11)
[info]   at testingModels.RegularUserModels.DirectUserStoreTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply$mcV$sp(DirectUserStoreTest.scala:28)
[info]   at testingModels.RegularUserModels.DirectUserStoreTest$$anonfun$1$$anonfun$apply$mcV$sp$1.apply(DirectUserStoreTest.scala:14)
[info]   ...
[info] Run completed in 2 seconds, 50 milliseconds.
[info] Total number of tests run: 1
[info] Suites: completed 1, aborted 0
[info] Tests: succeeded 0, failed 1, canceled 0, ignored 0, pending 0
[info] *** 1 TEST FAILED ***

请指导我如何实现我的目标。我知道我犯了一些大错误,但我需要指导,因此这是我一生中写的第一个测试 请帮忙

【问题讨论】:

  • 对于这样的持久层测试,我认为明确你想要检查的内容很重要。使用当前的模拟,您可以测试用户是否作为参数传递,我不确定这是否真的有价值。
  • 我想测试数据是否插入到mongoDB中......我插入的值是一样的
  • val DirectUserMock= createMock(classOf[directUserStore]) 如果您创建一个模拟,您将如何尝试测试directUserStore?您似乎对模拟实际上是什么感到困惑。您使用 Foo 的模拟来测试依赖于 Foo 的对象 Bar。如果你想测试你不想模拟的 MongoDB 的实际插入,你想测试你的实际代码。
  • 正如 vptheron 所说,如果您想在 write 之后测试 MongoDB 中存在的数据,那么它将是集成测试并需要一个测试数据库(可能还有设置它的装置)。对我来说有价值的是测试您的持久层是否根据您的函数的参数适当地调用 Mongo 驱动程序:检查持久层是否正在从自定义模型 BSON 执行适当的转换并按预期调用驱动程序插入。检查在 Mongo 集合上插入后,数据是否存在于该集合中,这对 MongoDB 引擎进行了相当大的测试。
  • 非常感谢您的帮助

标签: mongodb scala unit-testing easymock


【解决方案1】:

您打算成为 Mongo 客户端开发人员吗?否则,如果值在单元测试中存储在数据库中,则测试毫无意义(您可以在集成测试中执行此操作,但无论如何我都看不到一点)。 以可移植性为例 - 假设默认地址上存在 MongoDB 的单元测试将在没有安装 MongoDB 的任何其他计算机上失败。 其次 - 您必须假设某些事情正在工作 - 因此假设 MongoDB API 可以正常工作 - 是一个有效的假设。否则你可以质疑一切(字符串连接是否有效?为什么信任一个库而不是另一个库?) - 我想你明白我的意思

您实际应该测试的是您是否将正确的值传递给 Mongo API。这可以通过模拟来完成。 您可以使用ScalaMock,而我更喜欢使用Mockito,因为它可以很好地与Scala 配合使用并且具有更多可用功能。如果需要,可以将这两者结合起来。

您的课程 directUserStore 对某些无法更改的类具有不可替换的依赖项,因此很容易被模拟 - 例如 serverAddressclient - 它们可以移动到类级别的类。 然后,您可以使用模拟(例如由 Mockito 生成)覆盖它们,这将返回另一个模拟 collection 并验证是否在该集合上调用了正确的方法。

【讨论】:

  • 能否请您解释一下,请通过代码好吗?
  • ...或者您可以完全跳过模拟。 Scala 有足够的设施(例如好的特性),您通常可以构建更好的代码而无需模拟,也无需处理模拟库的内在复杂性(并非微不足道)。这只是我的拙见,但我之前已经多次看到这种论点。
  • 我不同意你的观点;验证您将正确的详细信息传递给 mongo API 仅验证您按照您认为应该使用的 API,而不是您已正确完成它。使用数据存储时,知道您是否正确完成了它的唯一方法是实际执行它。你对端口等做出假设是对的,所以这应该尽可能地通过测试或构建系统本身来控制,例如调出 mongo、docker/vagrant 等。
  • 您说的是集成测试,这就是设置 mongo 等合适的地方。问题是关于单元测试的,我确​​实认为单元测试应该尽可能独立。
【解决方案2】:

您不想在此级别的代码上进行模拟。您的 directUserStore 类负责与 MongoDb 交互、存储和检索数据。模拟 MongoDb 只会告诉您您已经以您认为应该的方式与 Mongo API 交互,不一定是正确的方式。

您应该在这里做的是启动一个 MongoDb 实例并往返您的数据。如果您只关心可以存储和读取数据,只需将其写入/读取并验证即可。如果您真的关心它的存储方式(提示:您可能不关心),那么您将不得不在测试中手动戳 MongoDb。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-14
    • 2014-06-23
    • 1970-01-01
    • 1970-01-01
    • 2013-10-11
    相关资源
    最近更新 更多