sarah w
sarah w

Reputation: 3505

how to use mocking in unit testing in scala

hi i am new in Unit Testing and i want to test it using mock objects .i want to test whether data is successfully stored in mongoDB or not here is my code

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 = "[email protected]"
       secondryEmail  =Some("[email protected]") 

        userStatus =ACTIVE

     }

And here is the class which i want to test

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())
                        )

  }

}

make an scala object to check code is working correctlly

object Test extends App{

val directUser= new DirectUser() 

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

Now i want to perform test on DirectUserStore.scala class ,So in src/test diectory of sbt i created this class

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)

          }
      }
    }
}    

but when i type test in sbt my test failed

[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 ***

please guide me how can i achieve my goal . i know i am doing some big mistake but i need guidance hence its the first test i am writing in my life help please

Upvotes: 0

Views: 2252

Answers (2)

tddmonkey
tddmonkey

Reputation: 21184

You don't want mocking at this level of code. Your directUserStore class is responsible for interacting with MongoDb, storing and retrieving data. Mocking out MongoDb will only tell you that you've interacted with the Mongo API in the way that you think you should, not necessarily the right way.

What you should do here is spin up a MongoDb instance and round-trip your data. If you only care that the data can be stored and read, just write it/read it back and verify it. If you really care about how it's stored (hint: you probably don't) then you will have to poke MongoDb manually in the tests.

Upvotes: 0

M4ks
M4ks

Reputation: 12024

Are you going to be Mongo client developer? Otherwise there is no point in testing if the value get stored in the DB in Unit Tests (you can do this in Intergration test, but I don't see a point anyway). Think for example of portability - unit tests assuming existence of MongoDB on default address will fail on any other computer without a MongoDB installed. Secondly - You have to assume some things are working - and hence that assumption that MongoDB API works as it should - is a valid assumption. Otherwise you can question everything (is string concatenation working or not? Why trust one library over another?) - I guess you see my point

What you should actually test is whether you pass the correct values to the Mongo API. This can be done by mocking. You can use ScalaMock while I prefer to use Mockito as it works well with Scala and have more functionality available. No problems with combining those two if you need.

Your class directUserStore has unreplacable dependecies to some classes that can't be changes and therefore easily mocked - for example serverAddress and client - they can be moved to class level ones. Then, you can override them with a mock (generated for example by Mockito), which will return another mock of collection and verify, if the correct methods were called on that collection.

Upvotes: 3

Related Questions