Chapter 5. Mocking

As we’ve discussed previously, one of the basic tenets of test-driven development is that each test has to be isolated. This means that the test doesn’t connect to the Internet, a database, or even the production file system. Typically, these foreign systems are represented through some kind of stunt double to the production object. The following definitions of stunt doubles come from Martin Fowler’s blog entry Mocks aren’t Stubs.

Dummy
An object that does nothing except fill in space. Any calls that it receives will neither change anything nor record anything.
Stub
An object that can consume test behavior and generate some result. It is meant to provide precreated answers for the test. Stubs can be used for recording and analysis to determine the number of calls that are made. They typically require more work than dummies, and an abundance of classes need to be created.
Fake
A fake object is a real object that overrides the more difficult stuff by providing a shortcut.
Mock
An object that is given orders to carry out a prescribed set of commands when it is called upon. This is analogous to the stand-in opponent during preparation for a political debate. The opponent would likely be a campaign team member, but she will have a set of answers already prepared to debate the candidate who needs to train for the big event.

Dummy objects have been used extensively in this book. Consider what we did in covering a Specs2 unit specification. In order to test out our Jukebox we created an Album (that’s not the dummy); we also created some Track instances to store in the Album (not dummies either). But in order to make the whole thing work we needed an Act, so we added the band Above and Beyond. It wasn’t really necessary, except we wanted to put something in the parameter so we could move along with our test.

src/test/java/com/oreilly/testingscala/JukeboxUnitSpec.scala

class JukeboxUnitSpec extends Specification {
  "A Jukebox" should {
    """have a play method that returns a copy of the jukebox that selects
       the first song on the first album as the current track""" in {
      val groupTherapy = new Album("Group Therapy", 2011,
        Some(List(new Track("Filmic", "3:49"),
          new Track("Alchemy", "5:17"),
          new Track("Sun & Moon", "5:25"),
          new Track("You Got to Go", "5:34"))), new Band("Above and Beyond"))
      val jukebox = new JukeBox(Some(List(groupTherapy)))
      val jukeboxNext = jukebox.play
      jukeboxNext.currentTrack.get.name must be_==("Filmic")
      jukeboxNext.currentTrack.get.period must be_==(new Period(0, 3, 49, 0))
    }
  }
}

For a fake example, let’s create a trait called DAO which will persist any object to some sort of datastore, whether it be a file system or a database. This trait will be used throughout the chapter to highlight fakes, stubs, and mocks from different libraries EasyMock, Mockito, and ScalaMock. Since DAO is a trait, it is intended to be mixed into a class with a concrete implementation that is tied to a specific type of datastore. Possible names could be MySQLDAO, Oracle10DAO, MongoDBDAO, etc. Using a trait in this manner also promotes loose decoupling, since there is no strict shotgun marriage to any particular datasource. The DAO trait has one method, persist, whose job is to accept an input parameter is and persist it to a faked, stubbed, or mocked datastore.

src/test/scala/com/oreilly/testingscala/DAO.scala

package com.oreilly.testingscala

trait DAO {
  def persist[T](t:T)
}

A fake object is a real object but is a substitute for the real thing. Fakes are typically some sort of holder of a byte array or a map that will store any data that is persisted, reread, or manipulated. Fakes can also be in-memory databases that store the data, like HSQLDB or H2, which are full-fledged databases that can be datastores in memory. Please consider, though, that for TDD purposes that may still too much work to set up and defeats the purpose of unit test isolation required for test-driven development.

To make the DAO a fake we can either create a DAO object that has an underlying hash table or use an in-memory database. To keep this example short, we will use a Map to store all entries. For all intents, this fake object is actually a DAO, just not a very good one for production purposes since it is just a simple store to handle all transactions. Its raison d'être is to serve the test.

src/test/com/oreilly/testingscala/UsingFakeUnitSpec.scala

package com.oreilly.testingscala

import org.specs2.mutable.Specification

class FakeDAO extends DAO {
  var map = Map[Long, Any]()
  var count = 0L

  def persist[T](t: T) {
    map = map + (count -> t)
    count = count + 1
  }

  def persistCount = map.size
}

class UsingFakeUnitSpec extends Specification {
  "When two albums are added to the fake DAO the albums should be stored" in {
    val dao = new DAOStub
    dao.persist(new Album("The Roaring Silence", 1976, new Band("Manfred Mann's Earth Band")))
    dao.persist(new Album("Mechanical Animals", 1998, new Artist("Marilyn", "Manson")))
    dao.persistCount must be_==(2)
  }
}

In the above DAO, the first class is the fake, and accepts any object to be persisted. The extra method contains a persistCount method that would give us a current count of objects stored. When persist is called, it is handled and mimics the database as we intended. Inside of the fake is a Map object that handles all the entries. A count variable keeps track of the ID count of all entries. It’s rough, simple, and not very sexy, but again, it is just meant to serve the test—just as the punching bag is meant to serve the boxer in training.

Next, a Stub object is just an object that has some sort of logic developed into the code for assertion purposes. Sometimes it is easier to create a stub than to fuss with some sort of fake or mocking framework, because you just need something with some canned answers and you need it quick. The stub object can be as light or complex as you wish to develop it. It would be recommended that if it gets too complicated, then it will be time to change it out for a mock instead.

For the stub, here is an example of a DAOStub and a Specs2 Unit Specification that tracks as many times that a persist call is made. The test in the Specification uses the stub, persists two albums and we then assert that the count is 2. This example of course is painfully easy but shows the use of a Stub in testing situations.

src/test/scala/com/oreilly/testingscala/UsingStubUnitSpec.scala

package com.oreilly.testingscala

import org.specs2.mutable.Specification

class DAOStub extends DAO {
  var count = 0

  def persist[T](t: T) {
    count = count + 1
  }

  def persistCount = count
}

class UsingStubUnitSpec extends Specification {

  "Create 2 albums that we will persist to a stub DAO" in {
    val dao = new DAOStub
    dao.persist(new Album("The Roaring Silence", 1976, new Band("Manfred Mann's Earth Band")))
    dao.persist(new Album("Mechanical Animals", 1998, new Artist("Marilyn", "Manson")))
    dao.persistCount must be_==(2)
  }
}

You can argue that the stub looks similar to the fake. Keep in mind that a fake is an actual implementation of the trait or object you are creating a stunt double for, while a stub is a double that can accept your request but will give you canned answers in return.

Earlier I mentioned that if a stub gets too complicated it would be best to move to a mocking framework. The complication in this example would occur if we add more methods to the DAO, or when the intent of each method becomes difficult with a large permutation of scenarios. Let’s create another stub where after one persist, the next persist throws some sort of exception. [4]

src/test/com/oreilly/testingscala/UsingStubUnitSpec.scala

package com.oreilly.testingscala

import org.specs2.mutable.Specification

class DAOStubWithExceptionAfterTheFirstPersist extends DAO {
  var alreadyCalledOnce = false

  def persist[T](t: T) {
    if (alreadyCalledOnce) throw new RuntimeException("Unable to store")
    alreadyCalledOnce = true
  }
}

class UsingStubWithExceptionUnitSpec extends Specification {

  "Create 2 albums that we will persist to a stub DAO" in {
    val dao = new DAOStubWithExceptionAfterTheFirstPersist
    dao.persist(new Album("The Roaring Silence", 1976, new Band("Manfred Mann's Earth Band")))
    dao.persist(new Album("Mechanical Animals", 1998, new Artist("Marilyn", "Manson"))) must throwA[RuntimeException]
  }
}

But a question arises: how many different stub classes would we have to make for every conceivable use case scenario? This is why mocking easily becomes the best solution. Each of the different test doubles—fakes, dummies, and stubs—has benefits and drawbacks. Some criteria to consider include how long each will take, whether you have to handle side effects, whether you are representing a large system, and whether you are representing a system over a network. A rule of thumb is to use stubs and fakes in unit tests if they can be created quickly and can be managed easily. If they do not, there is good reason to put some investment in creating mocks.

EasyMock

EasyMock was the founding father of Java mocking and set the standard for mocking in the JVM. Today it is still highly favored by many TDDers and works great with any Java bytecode language, including Scala.

EasyMock, like other mocking frameworks, can be compared to a rehearsal. Imagine someone who wants to enter a singles bar hoping to attract the right person. The single man or lady may rehearse in the mirror some catchy lines or a flirtatious move. When ready and satisfied with their results, they enter the club and hope they get some positive interaction.

EasyMock works similar by creating the mock, rehearsing the mock with expected behavior, rewinding the behavior back to the beginning, and sending the mock into the test method to act out what was rehearsed. If there are expected results from the rehearsal, then one may verify that expected calls were actually made. Any unexpected calls that were made notify the programmer that the method wasn’t expecting the call. Let’s look at mocking in relation to a database, because that’s the resource one often has to reproduce for a test.

To install EasyMock, add the easymock dependency to the build.sbt file. The following shows just the dependencies in the file, excluding the rest of it.

//Code removed for brevity

libraryDependencies ++= Seq(
  "org.scalatest" % "scalatest_2.9.2" % "1.8" % "test" withSources() withJavadoc(),
  "joda-time" % "joda-time" % "1.6.2" withSources() withJavadoc(),
  "junit" % "junit" % "4.10" withSources() withJavadoc(),
  "org.testng" % "testng" % "6.1.1" % "test" withSources() withJavadoc(),
  "org.specs2" %% "specs2" % "1.12.3" withSources() withJavadoc(),
  "org.easymock" % "easymock" % "3.1" withSources() withJavadoc())

//Code removed for brevity

For our mocks, we will also the DAO trait, as we have done already in this chapter. Here it is again, so you don’t have to turn back.

package com.oreilly.testingscala

trait DAO {
  def persist[T](t: T)
}

EasyMock originally was used to mock only interfaces in Java (which have been replaced by traits in Scala). Newer generations, including the latest EasyMock, can mock actual concrete classes.

The following example tests a class named JukeboxStorageService, whose purpose is to persist the contents of a JukeBox into any kind of datastore. The JukeboxStorageService requires the help of two DAOs, one that stores an Album and another that stores an Act, which is the superclass of Band and Artist. The test case will start off simply so as not to overwhelm you.

src/test/scala/com/oreilly/testingscala/JukeboxStorageServiceEasyMockSpec.scala

package com.oreilly.testingscala

import org.scalatest.matchers.MustMatchers
import org.scalatest.Spec
import org.easymock.EasyMock._

class JukeboxStorageServiceEasyMockSpec extends Spec with MustMatchers {
  describe("A Jukebox Storage Service") {
    it("should use easy mock to mock out the DAO classes") {
       val daoMock = createMock(classOf[DAO])
    }
  }
}

The example creates a mock of the DAO using the createMock method, which is a static method of the EasyMock class. (Remember that EasyMock was written in Java, not Scala, if by chance you’re wondering where the static came from.) The third import statement uses a wildcard of the class to make any Java static methods or Scala object methods available for use within the class. If you don’t want to import the method directly for some reason, just import org.easymock.EasyMock, and write out the class with each call: EasyMock.createMock instead of the lighter alternative used here, createMock.

These mocks will be injected into the JukeboxStorageService class, which will be a subject under test that uses the DAO.

The next step is to set up any stubs or concrete models used in the test. The following example creates some Bands and Artists to give to the JukeboxStorageService so it can store that into our (mocked) datastore.

src/test/scala/com/oreilly/testingscala/JukeboxStorageServiceEasyMockSpec.scala

package com.oreilly.testingscala

import org.scalatest.matchers.MustMatchers
import org.scalatest.Spec
import org.easymock.EasyMock._

class JukeboxStorageServiceEasyMockSpec extends FunSpec with MustMatchers {
  describe("A Jukebox Storage Service") {
    it("should use easy mock to mock out the DAO classes") {
      // previous code removed for brevity

      //set up actual values to be used.
      val theGratefulDead: Band = new Band("Grateful Dead")
      val wyntonMarsalis: Artist = new Artist("Wynton", "Marsalis")
      val psychedelicFurs: Band = new Band("Psychedelic Furs")
      val ericClapton: Artist = new Artist("Eric", "Clapton")

      val workingmansDead = new Album("Workingman's Dead", 1970, None, theGratefulDead)
      val midnightToMidnight = new Album("Midnight to Midnight", 1987, None, psychedelicFurs)
      val wyntonAndClapton = new Album("Wynton Marsalis and Eric Clapton play the Blues", 2011, None,
        wyntonMarsalis, ericClapton)

      val jukeBox = new JukeBox(Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))
    }
  }
}

The example creates two bands (Grateful Dead and Psychedelic Furs) and two artists (jazz great Wynton Marsalis and guitar genius Eric Clapton). Next it creates some albums from the four bands and artists to be used in a JukeBox. The last concrete class used in the test is a jukeBox that contains all the Albums.

In the above example, since we’ve covered the ScalaTest FunSpec already in Chapter 3, I’ll focus here on the use of the EasyMock elements. First, a little more detail on DAO. Each DAO is a trait, and createMock instruments that trait to intercept all calls during testing. createMock accepts the name of the class that it will be mocking. As a Scala aside, classOf[DAO] in Scala is the same as AlbumDAO.class in Java: it merely retrieves the class from the type.

For the next step, we need the actual JukeboxStorageService, which requires one DAO parameter at the time of creation. This is where we will provide the DAO mock. In a real-life system, an actual concrete implementation tied to an actual storage system would be used. Since this is test-driven development and we need to be fast, the mocks will take their place.

src/test/scala/com/oreilly/testingscala/JukeboxStorageServiceEasyMockSpec.scala

package com.oreilly.testingscala

import org.scalatest.matchers.MustMatchers
import org.scalatest.Spec
import org.easymock.EasyMock._

class JukeboxStorageServiceEasyMockSpec extends FunSpec with MustMatchers {
  describe("A Jukebox Storage Service") {
    it("should use easy mock to mock out the DAO classes") {

     val daoMock = createMock(classOf[DAO])
     //Code omitted for brevity

     //create the subject under test
      val jukeboxStorageService = new JukeboxStorageService(daoMock)
   }
  }
}

Next comes the rehearsal. Each mock will be given “lines” that it needs to act out when called upon by the test.

package com.oreilly.testingscala

import org.scalatest.matchers.MustMatchers
import org.scalatest.Spec
import org.easymock.EasyMock._

class JukeboxStorageServiceEasyMockSpec extends Spec with MustMatchers {
  describe("A Jukebox Storage Service") {
    it("should use easy mock to mock out the DAO classes") {

      //previous lines omitted for brevity

      //set up expectations
      albumMock.persist(workingmansDead)
      albumMock.persist(midnightToMidnight)
      albumMock.persist(wyntonAndClapton)

      actMock.persist(theGratefulDead)
      actMock.persist(psychedelicFurs)
      actMock.persist(wyntonMarsalis)
      actMock.persist(ericClapton)
    }
  }
}

Each mock will need to be told what to expect. AlbumMock should expect that three albums—Workingman’s Dead, Midnight To Midnight, and Wynton and Clapton—will be the parameters of persist in the DAO of Album. In the mock for Act, persist is expected to be called for two band—The Grateful Dead and Psychedelic Furs—and two artists—Wynton Marsalis and Eric Clapton. These expectations don’t have to happen in order, they merely have to take place for the test to succeed.

When we created the mock for the DAO using val daoMock = createMock(classOf[DAO]), by default, EasyMock will only check that the expectations were run, but not in any particular order, only that they were called. If ordering expectations is important to you, create a mock with createStrictMock instead of createMock. This would instruct EasyMock to expect your expectation in the order that you provide during rehearsal in your test.

Now that each mock has rehearsed its part, it’s time to rewind the behavior by calling replay, calling persist on the subject under test jukeboxStorageService, and verifying the results.

package com.oreilly.testingscala

import org.scalatest.matchers.MustMatchers
import org.scalatest.Spec
import org.easymock.EasyMock._

class JukeboxStorageServiceEasyMockSpec extends Spec with MustMatchers {
  describe("A Jukebox Storage Service") {
    it("should use easy mock to mock out the DAO classes") {
      //previous line omitted for brevity

      //replay, more like rewind
      replay(daoMock)

      //make the call
      jukeboxStorageService.persist(jukeBox)

      //verify that the calls expected were made
      verify(daoMock)
    }
  }
}

replay rewinds all the mocks to set out to perform the prescribed actions we rehearsed. jukeboxStorageService.persist is the actual call to the test, as it sends in a jukeBox concrete object. The last line verifies that the mocks acted out what was intended. Running the test now will end in failure, so we can now work on satisfying the test. A few minutes later, perhaps something like the following example would be what the JukeboxStorageService class would like with the behavior that satisfies the test.

src/main/scala/com/oreilly/testingscala/JukeboxStorageService.scala

package com.oreilly.testingscala

class JukeboxStorageService(dao:DAO) {
  def persist(jukeBox:JukeBox)  {
    jukeBox.albums.getOrElse(Nil).foreach{
      album => dao.persist(album)
      album.acts.foreach(act => dao.persist(act))
    }
  }
}

The persist method, at least for this implementation, gets all the albums, if there are any. getOrElse is a method on Option that returns the contents of Some—in this case a list of albums—or generates an empty list Nil if there are no albums. The forEach method, running on the return value of getOrElse, iterates through the list of albums. album => dao.persist(album) takes each album from the albums List and calls persist on the DAO. Finally, for every act associated with the album, each one will be sent to dao for persistence.

Running the JukeboxStorageServiceEasyMockSpec will now succeed.

> test-only com.oreilly.testingscala.JukeboxStorageServiceEasyMockSpec
[info] Compiling 1 Scala source to /home/danno/testing_scala_book.svn/testingscala/target/scala-2.9.1/classes...
[info] JukeboxStorageServiceEasyMockSpec:
[info] A Jukebox Storage Service
[info] - should use easy mock to mock out the DAO classes
[info] Passed: : Total 1, Failed 0, Errors 0, Passed 1, Skipped 0
[success] Total time: 9 s, completed Jan 7, 2012 11:12:34 PM

This introduction to EasyMock has not been specific to Scala, since this technology has been used for years in Java. EasyMock does contain specific support for ScalaTest, which offers easier ways to work EasyMock.

EasyMock with ScalaTest

ScalaTest offers an EasyMockSugar trait that turns replaying and verifying into behind-the-scenes affairs, letting the test developer focus on the rehearsal and running the test. The example we established in the previous section is rewritten here but putting into place some of the sugar.

/src/test/scala/com/oreilly/testingscala/JukeboxStorageServiceEasyMockWithSugarSpec.scala

package com.oreilly.testingscala

import org.scalatest.Spec
import org.scalatest.matchers.MustMatchers
import org.scalatest.mock.EasyMockSugar
import org.easymock.EasyMock._

class JukeboxStorageServiceEasyMockWithSugarSpec extends Spec with MustMatchers with EasyMockSugar {
  describe("A Jukebox Storage Service") {
    it("should use easy mock sugar in ScalaTest") {
      val daoMock = createMock(classOf[DAO])

      //set up actual values to be used.
      val theGratefulDead: Band = new Band("Grateful Dead")
      val wyntonMarsalis: Artist = new Artist("Wynton", "Marsalis")
      val psychedelicFurs: Band = new Band("Psychedelic Furs")
      val ericClapton: Artist = new Artist("Eric", "Clapton")

      val workingmansDead = new Album("Workingman's Dead", 1970, None, theGratefulDead)
      val midnightToMidnight = new Album("Midnight to Midnight", 1987, None, psychedelicFurs)
      val wyntonAndClapton = new Album("Wynton Marsalis and Eric Clapton play the Blues", 2011, None,
        wyntonMarsalis, ericClapton)

      val jukeBox = new JukeBox(Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))

      //create the subject under test
      val jukeboxStorageService = new JukeboxStorageService(daoMock)

      expecting {
        daoMock.persist(workingmansDead)
        daoMock.persist(midnightToMidnight)
        daoMock.persist(wyntonAndClapton)

        daoMock.persist(theGratefulDead)
        daoMock.persist(psychedelicFurs)
        daoMock.persist(wyntonMarsalis)
        daoMock.persist(ericClapton)
      }

      whenExecuting(daoMock) {
        jukeboxStorageService.persist(jukeBox)
      }
    }
  }
}

To compare this latest example with the plain ScalaTest/EasyMock example in the previous section, replay and verify are gone. Their place is taken by some new methods provided by the EasyMockSugar trait: expecting and whenExecuting.

expecting is a function block that just offers a visual categorization of what the mocks expect to be passed, all in one tidy place. whenExecuting wraps the replaying and verifications without extra effort.

As always, ScalaTest tries here to give its assertions and set up a fluid linguistic flow. The syntactical sugar used for EasyMock is just another way of doing so. Chapter 6 covers ScalaCheck, and even some more nice syntactic sugar to make testing even easier.

Mockito

Mockito is a later-generation testing framework used mostly in Java. One of the distinct differences between Mockito and ScalaTest is that, in Mockito, mocks don’t have to be replayed. Mockito was the first framework to have mocking for a concrete class, but since then EasyMock has also included support for class testing. Mockito also offers Hamcrest integration so that each parameter can have a wild card parameter as part of the assertion.

To set up Mockito for use in SBT, merely include the latest Mockito version (1.9.0 at the time of this writing) within the build.sbt file.

libraryDependencies ++= Seq("org.scalatest" %% "scalatest" % "1.8" % "test" withSources() withJavadoc(),
  "joda-time" % "joda-time" % "1.6.2" withSources() withJavadoc(),
  "junit" % "junit" % "4.10" withSources() withJavadoc(),
  "org.testng" % "testng" % "6.1.1" % "test" withSources() withJavadoc(),
  "org.specs2" %% "specs2" % "1.12.3" % "test" withSources() withJavadoc(),
  "org.easymock" % "easymock" % "3.1" % "test" withSources() withJavadoc(),
  "org.mockito" % "mockito-core" % "1.9.0" % "test" withSources() withJavadoc())

Mockito works well in ScalaTest and Specs2. In Specs2, since all testing must result in something that needs to return a Result type, Mockito requires special tweaking to work well. Luckily, Specs2 offers a host of sugar for Mockito, although ScalaTest does not. This section will use Mockito both in its raw form and with Specs2 special sugars and DSL to manage mocks better.

The process of using Mockito is nearly the same as using EasyMock. Set up the mocks, rehearse the objects, run the test, and verify. There’s no replaying or rewinding the mocks. The following example uses Mockito in a Specs2 acceptance specification.

src/test/scala/com/oreilly/testingscala/JukeboxStorageServiceMockitoAcceptanceSpec.scala

package com.oreilly.testingscala

import org.specs2.Specification
import org.mockito.Mockito._

class JukeboxStorageServiceMockitoAcceptanceSpec extends Specification {
  def is = {
    "You can use Mockito to perform Scala mocking" ! useMockitoToMockClasses
  }

  def useMockitoToMockClasses = {
    val daoMock = mock(classOf[DAO])

    //set up actual values to be used.
    val theGratefulDead: Band = new Band("Grateful Dead")
    val wyntonMarsalis: Artist = new Artist("Wynton", "Marsalis")
    val psychedelicFurs: Band = new Band("Psychedelic Furs")
    val ericClapton: Artist = new Artist("Eric", "Clapton")

    val workingmansDead = new Album("Workingman's Dead", 1970, None, theGratefulDead)
    val midnightToMidnight = new Album("Midnight to Midnight", 1987, None, psychedelicFurs)
    val wyntonAndClapton = new Album("Wynton Marsalis and Eric Clapton play the Blues", 2011, None,
      wyntonMarsalis, ericClapton)

    val jukeBox = new JukeBox(Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))

    //create the subject under test
    val jukeboxStorageService = new JukeboxStorageService(daoMock)

    //no replay

    //make the call
    jukeboxStorageService.persist(jukeBox)

    //verify that the calls expected were made
    verify(daoMock).persist(theGratefulDead)
    verify(daoMock).persist(workingmansDead)
    success
  }
}

Instead of createMock, Mockito uses a mock method to generate the mocks. The sample uses a number of concrete methods available for tests. Again, there is no replay involved. The verification syntax is also very different. The verify method just accepts the mock, at which point another method can be called to verify the behavior. In other words, the last lines of the acceptance specification shown here are of the form verify(mock).method(params), where method is the method that is expected to be called and the parameters given are the parameters that were expected to be delivered. If any verification fails, an exception is thrown. For example, one feature of testing frameworks, including EasyMock, is that the developer can specify how many times a particular method can be called with a given parameter. The developer is free to explicitly state that a method should never be called, or that a method should be called 10 times.

In Mockito, you can specify the number of times a method should be called with a VerificationMode in the verify method. If, for example, a verification should fail, the last verify statement can be amended to state:

verify(albumMock, never()).persist(workingmansDead)

Doing so will cause an exception and a test failure—not the nice kind where it shows up in a report but with a visually abhorrent stack trace.

[info] Compiling 1 Scala source to /home/danno/testing_scala_book.git/testingscala/target/scala-2.9.0-1/test-classes...
[error] x You can use Mockito to perform Scala mocking
[error]
[error] dAO.persist(
[error]     com.oreilly.testingscala.Album@202d0e83
[error] );
[error] Never wanted here:
[error] -> at com.oreilly.testingscala.JukeboxStorageServiceMockitoAcceptanceSpec.useMockitoToMockClasses(JukeboxStorageServiceMockitoAcceptanceSpec.scala:38)
[error] But invoked here:
[error] -> at com.oreilly.testingscala.JukeboxStorageService$$anonfun$persist$2.apply(JukeboxStorageService.scala:7)
[error]  (JukeboxStorageServiceMockitoAcceptanceSpec.scala:8)
[info]
[info] Total for specification JukeboxStorageServiceMockitoAcceptanceSpec
[info] Finished in 192 ms
[info] 1 example, 1 failure (+1), 0 error
[error] Failed: : Total 1, Failed 1, Errors 0, Passed 0, Skipped 0
[error] Failed tests:
[error]     com.oreilly.testingscala.JukeboxStorageServiceMockitoAcceptanceSpec
[error] {file:/home/danno/testing_scala_book.git/testingscala/}default-cef86a/test:test-only: Tests unsuccessful
[error] Total time: 2 s, completed Jan 6, 2012 2:24:06 PM

Mockito with Specs2

Specs2 comes with its own Mockito sugar [5] to create the necessary Result, and it includes a few language enhancements along the way. The next example revises the acceptance spec shown in the previous section, adding some Specs2 goodness.

package com.oreilly.testingscala

import org.specs2.Specification
import org.specs2.mock.Mockito

class JukeboxStorageServiceMockitoSugarAcceptanceSpec extends Specification with Mockito {
  def is = {
    "You can use Mockito to perform Scala mocking" ! useMockitoToMockClasses
  }

  def useMockitoToMockClasses = {
    val daoMock = mock[DAO] as "album mock"

    //set up actual values to be used.
    val theGratefulDead: Band = new Band("Grateful Dead")
    val wyntonMarsalis: Artist = new Artist("Wynton", "Marsalis")
    val psychedelicFurs: Band = new Band("Psychedelic Furs")
    val ericClapton: Artist = new Artist("Eric", "Clapton")

    val workingmansDead = new Album("Workingman's Dead", 1970, None, theGratefulDead)
    val midnightToMidnight = new Album("Midnight to Midnight", 1987, None, psychedelicFurs)
    val wyntonAndClapton = new Album("Wynton Marsalis and Eric Clapton play the Blues", 2011, None,
      wyntonMarsalis, ericClapton)

    val jukeBox = new JukeBox(Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))

    //create the subject under test
    val jukeboxStorageService = new JukeboxStorageService(daoMock)

    //no replay

    //make the call
    jukeboxStorageService.persist(jukeBox)

    //verify that the calls expected were made
    there was one (daoMock).persist(theGratefulDead)
    there was one (daoMock).persist(workingmansDead)
  }
}

The example mixes in the Mockito trait, which provides a different syntax that returns the Result type expected from a Specs2 test. The information in this test is not much different from a regular Mockito-based test, except for the matchers in the last two lines. The matchers use Specs2 language to verify the mock. there was one signifies that there was one call to the method persist with the object reference theGratefulDead on the mock actMock. Much like the other mocking frameworks, any mock can be specified with the number of times it should be called, either on the rehearsal or on the verification. Here we expect that one persist call is made for theGratefulDead and one for their album workingmansDead.

Using the Specs2 Mockito language, the developer can get fairly fancy with how to describe the number of times a particular mock is expected to be called. Some other Specs2 phrases include there was two, and, for those who favor good grammar, there were two. there were three, there were atLeastOne, there were atLeastTwo, there were atMostOne, there were atMostTwo, etc.

Order verification

To specify an order to operations using the Specs2 Mockito language, we set up chaining using a then method. For instance, we could rewrite the specification from the previous section to specify that an order is required, as follows:

there was one (actMock).persist(theGratefulDead) then one (albumMock).persist(workingmansDead)

ScalaMock

ScalaMock is a mocking framework that is all Scala, and meant for Scala only. Its purpose as a mocking framework is to get into some of the hardest testing spots in Scala, such as functions, singleton objects, companion objects, static methods, final objects, and final methods. ScalaMock can also mock traits and concrete classes like the other mocking frameworks.

ScalaMock was originally called Borachio but has taken on a new name. The original Borachio framework supported only traits and functions, but of late supports a wide range of Scala construct, and is ever-growing. ScalaMock works only with SBT, since it uses an SBT compiler plug-in. This is essential to create an action called generate-mocks that is used to create bytecode of the mocks in order to use them.

Using ScalaMock with SBT calls for a bit more setup than most frameworks we’ve seen. You have to delete the build.sbt file in favor of a Scala-based build file. SBT works with two types of build files. One is the .sbt file we’ve seen, a user-friendly format where you can set up dependencies, names, versions and the like. But in order to do something a little more complicated, you instead need a .scala build file.

After deleting build.sbt, create project/project/Build.scala and project/TestingScala.scala. The first file will define the compiler plug-in used to generate the mocks, while the second will be the actual build file. Insert the following into /project/project/Build.scala:

project/project/Build.scala

import sbt._

object PluginDef extends Build {
  override lazy val projects = Seq(root)
  lazy val root = Project("plugins", file(".")) dependsOn(scalamockPlugin)
  lazy val scalamockPlugin = uri("git://github.com/paulbutcher/scalamock-sbt-plugin")
}

In SBT, these calls register the plug-in to be used within SBT and which projects to attach to. This Plugin definition will attach to the root project and retrieve the plug-in from a Git repository.

The new project file, project/TestingScala.scala, is the replacement to build.sbt. This file identifies some of the usual suspects. But whereas our original build.sbt was based on keys and values, this file is pure Scala code and looks like the following.

import sbt._
import Keys._
import ScalaMockPlugin._

object TestingScala extends Build {

  override lazy val settings = super.settings ++ Seq(
    organization := "com.oreilly.testingscala",
    version := "1.0",
    scalaVersion := "2.9.2",

    resolvers += ScalaToolsSnapshots,
    resolvers ++= Seq("snapshots" at "http://oss.sonatype.org/content/repositories/snapshots",
                      "releases"  at "http://oss.sonatype.org/content/repositories/releases"),
    libraryDependencies ++= Seq("org.scalatest" %% "scalatest" % "1.8" % "test" withSources() withJavadoc(),
      "joda-time" % "joda-time" % "1.6.2" withSources() withJavadoc(),
      "junit" % "junit" % "4.10" withSources() withJavadoc(),
      "org.testng" % "testng" % "6.1.1" % "test" withSources() withJavadoc(),
      "org.specs2" %% "specs2" % "1.12.3" % "test" withSources() withJavadoc(),
      "org.easymock" % "easymock" % "3.1" % "test" withSources() withJavadoc(),
      "org.mockito" % "mockito-core" % "1.9.0" % "test" withSources() withJavadoc(),
      "org.scalamock" %% "scalamock-scalatest-support" % "2.3-SNAPSHOT")),
    autoCompilerPlugins := true,
    addCompilerPlugin("org.scalamock" %% "scalamock-compiler-plugin" % "2.3-SNAPSHOT"),
    scalacOptions ++= Seq("-deprecation", "-unchecked")),

  lazy val myproject = Project("Testing Scala", file(".")) settings(generateMocksSettings: _*) configs(Mock)
}

The new build file contains the organization, version, and scalaVersion used for the project. resolvers, as before, are the Maven-based repositories that contain the dependencies. ScalaToolsSnapshots just includes the snapshots repository. ScalaToolsReleases is already included implicitly. The OSS Sonatype repositories were needed for Specs2. libraryDependencies, much like in the former build.sbt, contains all the dependencies, and there is a new dependency at the end of this Seq, ScalaMock.

Some new settings are included:

autoCompilerPlugins
Turns on the compiler plugin functionality.
addCompilerPlugin
Specifies which compiler plugin to use.
scalacOptions
Are not ScalaMock specific. They are merely compilation flags for the Scala compiler.

The last line of the build file contains the project name, indicates where the the root of the project is located, and adds the generateMockSettings and configuration required to load the mocked classes into the test.

Behind the scenes, ScalaMock creates classes based on the signatures of the classes specified by the developer that need mocking. This will be covered shortly.

To verify that the setup works, run reload and update in SBT, either on the shell command line or in interactive mode.

Mocking Traits

Mocking a trait is the most basic type of mocking, and ScalaMock, of course, supports it. Given the previous mocking examples in the book, for Mockito and EasyMock, the following example demonstrates the use of mocking using ScalaMock. Because ScalaMock provides its own support for traits, no extra setup is required for this example, but there will be extra setup for subsequent examples that mock other structures.

testingscala/src/test/scala/com/oreilly/testingscala/UsingScalaMockSample.scala

package com.oreilly.testingscala

import org.scalatest.Spec
import org.scalatest.matchers.MustMatchers
import org.scalamock.scalatest.MockFactory
import org.scalamock.generated.GeneratedMockFactory

class UsingScalaMockSample extends Spec with MustMatchers with MockFactory {
  describe("ScalaMocks can create mocks of traits") {
    it("can create a mock for a trait") {
      val daoMock = mock[DAO]

      //set up actual values to be used.
      val theGratefulDead: Band = new Band("Grateful Dead")
      val wyntonMarsalis: Artist = new Artist("Wynton", "Marsalis")
      val psychedelicFurs: Band = new Band("Psychedelic Furs")
      val ericClapton: Artist = new Artist("Eric", "Clapton")

      val workingmansDead = new Album("Workingman's Dead", 1970, theGratefulDead)
      val midnightToMidnight = new Album("Midnight to Midnight", 1987, psychedelicFurs)
      val wyntonAndClapton = new Album("Wynton Marsalis and Eric Clapton play the Blues", 2011, wyntonMarsalis, ericClapton)

      val jukeBox = new JukeBox(Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))

      //create the subject under test
      val jukeboxStorageService = new JukeboxStorageService(daoMock)

      daoMock.expects.persist(workingmansDead)
      daoMock.expects.persist(midnightToMidnight)
      daoMock.expects.persist(wyntonAndClapton)

      daoMock.expects.persist(theGratefulDead)
      daoMock.expects.persist(psychedelicFurs)
      daoMock.expects.persist(wyntonMarsalis)
      daoMock.expects.persist(ericClapton)

      jukeboxStorageService.persist(jukeBox)
   }
}

ScalaMock requires the type of the object that is to be mocked. In this example, mock[DAO] generates a mock of the DAO class, which is the mocked type. The subsequent lines, as before, are dummy objects for Bands, Artists, and Albums used to test the DAO. Each dummy object is placed into the JukeBox object, which will be used inside the jukeboxStorageService.

After creating the JukeboxStorageService, the expectations on the mock are created. daoMock expects that persist is called for all three albums: Workingmans Dead, Midnight to Midnight, and Wynton and Clapton. In the next set, expectations are made for the two bands, the Grateful Dead and the Psychedelic Furs. Finally come expectations for the artists, Wynton Marsalis and Eric Clapton.

To invoke the tests, a call to persist is made on the jukeboxStorageService object. Again, the only difference is the setup. Testing for traits in ScalaMock is similar to EasyMock and Mockito. But where ScalaMock will leave its competitors in the dust is in its ability to test things such as functions, objects, companion objects, final classes, and methods.

Mocking Classes

Like Mockito and EasyMock, ScalaMock can mock concrete classes. To use it, you must run the generate-mocks compiler plug-in by calling generate-mocks in sbt before running your test. generate-mocks generates instrumented classes in the target/scala-version/mock-classes folder of the project. These classes will be substituted for the real classes during the text. The command also installs a trait named org.scalamock.generated.GeneratedMockFactory. The trait will be compiled when generated.

Therefore at the time of compilation, the developer will not see this trait as if it is something concrete. For most developers working in IDEs, the trait would be highlighted in some way, such as appearing red.

After the setup has been completed, the shell of the test should look like the following example. When viewing the sample, notice that we include an import statement for org.scalamock.generated.GeneratedMockFactory and extend it as a trait.

/src/test/scala/com/oreilly/testingscala/UsingScalaMockSample.scala

package com.oreilly.testingscala

import org.scalatest.Spec
import org.scalatest.matchers.MustMatchers
import org.scalamock.scalatest.MockFactory
import org.scalamock.generated.GeneratedMockFactory

class UsingScalaMockSample extends Spec with MustMatchers with MockFactory with GeneratedMockFactory {
   //Put tests here.
}

To create a mock for a concrete class, a declaration must be made that the class is to be mocked. In order to achieve that, a new class needs to be created with different categorization.

In the src folder of the project, create a folder named generate-mocks that is a sibling of main and test. Within the generate-mocks folder, create a folder named scala. Within the scala folder, which is now a folder on the classpath, a dummy class needs to be created. The name of the class doesn’t matter. It is a placeholder for annotations that detail which classes should be mocked and how they should be mocked. Figure 5-1 shows a sample layout for the projects in this book.

Folder arrangement for the generate-mocks folder

Figure 5-1. Folder arrangement for the generate-mocks folder

In the following example, the placeholder class will be called GenerateMocks. To reemphasize, this class that you create can be called whatever you would like. Above of the dummy class will be annotations for all mocks, companion, and singleton mocks that are required to test the class.

/src/generate-mocks/scala/GenerateMocks.scala

import com.oreilly.testingscala._
import org.scalamock.annotation.{mock}

@mock[Artist]
@mock[Album]
@mock[Track]
class GenerateMocks

Once the annotations are in place on the dummy class, ScalaMock will use the annotations to create mock classes that will be used in place of the actual classes. The test for our next example requires mocks for the Artist, Band, and Album classes.

/src/test/scala/com/oreilly/testingscala/UsingScalaMockSample.scala

package com.oreilly.testingscala

import org.scalatest.Spec
import org.scalatest.matchers.MustMatchers
import org.scalamock.scalatest.MockFactory
import org.scalamock.generated.GeneratedMockFactory


class UsingScalaMockSample extends Spec with MustMatchers with MockFactory with GeneratedMockFactory {

  describe("ScalaMocks can create mocks of various structures") {
    //Previous test omitted for brevity

    it("can also mock regular object, and along with other traits") {
      val daoMock = mock[DAO]
      //set up actual values to be used.
      val theGratefulDead: Band = mock[Band]
      val wyntonMarsalis: Artist = mock[Artist]
      val psychedelicFurs: Band = mock[Band]
      val ericClapton: Artist = mock[Artist]

      val workingmansDead = mock[Album]
      val midnightToMidnight = mock[Album]
      val wyntonAndClapton = mock[Album]

      val jukeBox = mock[JukeBox]

      //create the subject under test
      val jukeboxStorageService = new JukeboxStorageService(daoMock)

      inSequence {
        jukeBox.expects.albums returning (Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))

        daoMock.expects.persist(workingmansDead)
        workingmansDead.expects.acts returning (List(theGratefulDead))
        daoMock.expects.persist(theGratefulDead)

        daoMock.expects.persist(midnightToMidnight)
        midnightToMidnight.expects.acts returning (List(psychedelicFurs))
        daoMock.expects.persist(psychedelicFurs)

        daoMock.expects.persist(wyntonAndClapton)
        wyntonAndClapton.expects.acts returning (List(ericClapton, wyntonMarsalis))
        daoMock.expects.persist(ericClapton)
        daoMock.expects.persist(wyntonMarsalis)
      }

      jukeboxStorageService.persist(jukeBox)
    }
}

This example creates mocks out of the concrete classes Band, Artist, Album, JukeBox, and DAO. The test class, jukeboxStorageService, lists its assertions in order using the inSequence{..} block. If any of the calls are not made, or if they are made out of order, an org.scalamock.ExpectationException will be thrown. As before, after all the assertions have been made, the method call or calls to the subject under test can be made.

The following sample shows an sbt testing session using ScalaMock. As I mentioned before, you must call generate-mocks in sbt before the test.

> clean
[success] Total time: 0 s, completed Mar 15, 2012 8:47:45 PM
> generate-mocks
[info] Updating {file:/home/danno/testing_scala_book.svn/testingscala/}Testing Scala...
[info] Resolving joda-time#joda-time;1.6.2 ...
[info] Resolving junit#junit;4.10 ...
....
[info] Resolving org.scalamock#scalamock-compiler-plugin_2.9.1;2.3-SNAPSHOT ...
[info] Resolving org.scala-lang#scala-compiler;2.9.1 ...
[info] Done updating.
[info] Compiling 13 Scala sources to /home/danno/testing_scala_book.svn/testingscala/target/scala-2.9.1/classes...
[log generatemocks] Creating mock for: class Artist
[log generatemocks] Creating mock for: class Artist
....
[log generatemocks] Creating mock for: class Track
[log generatemocks] Creating mock for: class Band
[log parser] parsing Iterator.class
[success] Total time: 25 s, completed Mar 15, 2012 8:48:18 PM
> test:compile
[info] Compiling 19 Scala sources to /home/danno/testing_scala_book.svn/testingscala/target/scala-2.9.1/mock-classes...
[info] Compiling 52 Scala sources to /home/danno/testing_scala_book.svn/testingscala/target/scala-2.9.1/test-classes...
[success] Total time: 99 s, completed Mar 15, 2012 8:51:44 PM
> ~test-only com.oreilly.testingscala.UsingScalaMockSample
[info] UsingScalaMockSample:
[info] ScalaMocks can create mocks of various structures
[info] - can create a mock for a trait
[info] - can also mock regular object, and along with other traits
[info] Passed: : Total 2, Failed 0, Errors 0, Passed 2, Skipped 0
[success] Total time: 1 s, completed Mar 15, 2012 8:52:02 PM
1. Waiting for source changes... (press enter to interrupt)

It is worth getting into the habit of calling generate-mocks each time a change is made to a class that is mocked, since the mock in current use doesn’t have the latest updates. Although this is somewhat inelegant now, there should be a more streamlined process in the future.

Mocking Singleton Objects

The strength of ScalaMock doesn’t stop there. It can also mock singleton objects. This in itself is perhaps the best selling point for ScalaMock. In the Java space, mocking static methods has often been a pain point for the test-driven developer. Such limitations caused us to rethink our programming structure, and not be so dependent on the static keyword, a blessing in disguise. Static methods are not used as heavily today, except for constructs like static factory methods in frameworks like Spring. In Scala, there is no static keyword, and therefore no static initializers, variables, or methods. In lieu of static, Scala uses object. It can be used either as a factory or as a declared instance of a class. A Java programmer coming to Scala can consider the object as a structure that houses methods and variables that would have been static in Java.

The following example shows a singleton class for The Boss—BruceSpringsteenFactory. The factory is there to create objects or a list of Album objects that created Bruce Springsteen. The artist method is used to create an Artist object representing Bruce. The discography method creates a List of Album objects representing some of his earlier works, and finally the jukebox method creates a JukeBox object of all of Bruce’s work.

/src/main/scala/com/oreilly/testingscala/BruceSpringsteenFactory.scala

package com.oreilly.testingscala

object BruceSpringsteenFactory {
  private lazy val theBoss = {
    println("loaded the info");
    new Artist("Bruce", None, "Springsteen", Nil, Some("The Boss"))
  }

  def artist = discography.foldLeft(theBoss) {
    (boss, album) ⇒ boss.addAlbum(album)
  }

  def discography = List(
    new Album("Greetings from Ashbury Park, N.J.", 1973, None, theBoss),
    new Album("The Wild, The Innocent
& the E Street Shuffle", 1973, None, theBoss),
    new Album("Born To Run", 1975, None, theBoss),
    new Album("Darkness on the Edge of Town", 1978, None, theBoss),
    new Album("The River", 1980, None, theBoss),
    new Album("Nebraska", 1982, None, theBoss),
    new Album("Born in the USA", 1984, None, theBoss))

  def jukebox = new JukeBox(Some(discography))
}

What if this object is used within another object that happens to be the subject under test? That would make BruceSpringsteenFactory a prime candidate to be mocked. The next example is a test for a class named BruceSpringsteenStatistics, another object that provides statistics for Bruce Springsteen given the information provided by the singleton, BruceSpringsteenFactory.

/src/test/scala/com/oreilly/testingscala/UsingScalaMockSample.scala

package com.oreilly.testingscala

import org.scalatest.Spec
import org.scalatest.matchers.MustMatchers
import org.scalamock.scalatest.MockFactory
import org.scalamock.generated.GeneratedMockFactory

class UsingScalaMockSample extends Spec with MustMatchers with MockFactory with GeneratedMockFactory {
  describe("ScalaMocks can create mocks of various structures") {

    //Previous Tests omitted for brevity

    it("can mock a singleton object") {
      val bruceSpringsteenFactory = mockObject(BruceSpringsteenFactory)

      val albumMock1 = mock[Album]
      val albumMock2 = mock[Album]
      val albumMock3 = mock[Album]

      albumMock1.expects.year returning (1978)
      albumMock2.expects.year returning (1990)
      albumMock3.expects.year returning (1999)

      bruceSpringsteenFactory.expects.discography returning List(albumMock1, albumMock2, albumMock3)

      BruceSpringsteenStatistics.numberOfAlbums must be (3)
      BruceSpringsteenStatistics.averageYear must be ((1978 + 1990 + 1999) / 3)
    }
  }
}

In this example, BruceSpringsteenFactory is the singleton object to be mocked. BruceSpringsteenStatistics is another singleton, but is the subject under test. The point of the test is to derive the statistics from BruceStringsteenStatistics using test-driven development. mockObject is a method that creates a mock for the singleton. Note that mockObject uses parentheses whereas mock uses brackets. mockObject accepts the singleton as an argument in order to generate the mock.

The next lines create three mock Album objects and three expectations about those mocks: that the first album will return the year 1978, that the second album will return 1990, and that the third will return 1999. Next, the bruceSpringsteenFactory has an expectation that the discography method will be called and will return a list of the Album mocks that have been established. Finally, the last two lines assert that the numberOfAlbums and averageYear method will return the expected results.

Some additional setup is still required. The GeneratedMocks dummy class will need to be notified that the BruceSpringsteenFactory needs to be mocked. The following code snippet does this.

/src/generate-mocks/scala/GenerateMocks.scala

import com.oreilly.testingscala._
import org.scalamock.annotation.{mockWithCompanion, mockObject, mock}

@mock[Artist]
@mock[Album]
@mock[Track]
@mock[DAO]
@mock[JukeBox]
@mockObject(BruceSpringsteenFactory)
class GenerateMocks

This example is different from the first one in this section in that it uses @mockObject with the singleton as a parameter, instead of @mock, which takes a type parameter.

Now you should run clean, generate-mocks, and test:compile, and then test the class to let a failure happen. Implementing the class and satisfying the test would now somewhat look like the following example.

/src/main/scala/com/oreilly/testingscala/BruceSpringsteenStatistics.scala

package com.oreilly.testingscala

object BruceSpringsteenStatistics {
  def numberOfAlbums = BruceSpringsteenFactory.discography.size
  def averageYear = BruceSpringsteenFactory.discography.map(_.year).sum / numberOfAlbums
}

This is a huge advancement in testing, and the setup required to test tough scenarios like singletons is fairly minimal. For many testers, this is welcoming.

Mocking Companion Objects

In Scala, an object with the same name as a class is called a companion object. The role of a companion object is to offer factory methods for the accompanying class or trait and extractors for pattern matching, as well as house shared variables between objects created from the class. A companion object and its associated class also have access to each other’s members’ variables.

For an example of testing a companion object with ScalaMock, we’ll give the DAO trait some company: two classes that are implementations of the DAO trait, and a DAO companion object in charge of doling out the concrete implementations of the DAO.

/src/main/scala/com/oreilly/testingscala/DAO.scala

package com.oreilly.testingscala

trait DAO {
  def persist[T](t:T)
}

object DAO {
  private class MySqlDAO extends DAO {def persist[T](t:T){}}
  private class DB2DAO extends DAO {def persist[T](t:T){}}

  def createMySqlDAO:DAO = new MySqlDAO
  def createDB2DAO:DAO = new DB2DAO
}

The DAO object has the same name as the trait, and is therefore a companion to the trait. The companion object has two factory methods, one that will return a MySqlDAO object, and another that will return a DB2DAO object. The following code mocks the companion and hijacks createMySQLDAO and createDB2DAO to return the object that will be defined by the test programmer. The subject under test for the example will be a class called AlbumMultipleStorageService that uses the DAO companion object to obtain the data access objects for two different kinds of databases, one for mySQL, and one for DB2. AlbumMultipleStorageService then will use both of the DAOs to store the Artist, Peter Murphy, and then use both DAOs to store the album, Cascade.

/src/test/scala/com/oreilly/testingscala/UsingScalaMockSample.scala

package com.oreilly.testingscala

import org.scalatest.Spec
import org.scalatest.matchers.MustMatchers
import org.scalamock.scalatest.MockFactory
import org.scalamock.generated.GeneratedMockFactory


class UsingScalaMockSample extends Spec with MustMatchers with MockFactory with GeneratedMockFactory {
  describe("ScalaMocks can create mocks of various structures") {

    //previous tests omitted for brevity

    it("can mock a companion object") {
      val daoMockCompanion = mockObject(DAO)

      val daoMockMySql = mock[DAO]
      val daoMockDB2 = mock[DAO]

      val peterMurphy: Artist = new Artist("Peter", "Murphy")

      val cascade = new Album("Cascade", 1995, peterMurphy)

      daoMockCompanion.expects.createMySqlDAO returning (daoMockMySql)
      daoMockCompanion.expects.createDB2DAO returning (daoMockDB2)

      inSequence {
        daoMockMySql.expects.persist(cascade)
        daoMockDB2.expects.persist(cascade)
        daoMockMySql.expects.persist(peterMurphy)
        daoMockDB2.expects.persist(peterMurphy)
      }

      val albumMultipleStorageService = new AlbumMultipleStorageService()
      albumMultipleStorageService.persist(cascade);
    }
  }
}

mockObject is called with the singleton companion object that needs to be mocked for testing purposes. The DAO companion object will be used inside the AlbumMultipleStorageService to retrieve the two DAOs. After mocking the companion object, a regular trait mock is made for the mySQL DAO, and another for the DB2 DAO. Next, the Artist, Peter Murphy, is created, as well as his album, Cascade, with a reference to the artist object. This is followed by expectations of the companion object. The code inside of the inSequence block consists of expectations made to the mySQL and DB2 DAO mocks in the specified sequential order. Finally, the subject under test, AlbumMultipleStorageService, is instantiated, and the persist method is called with the album, Cascade.

A change must be made in the dummy class, GenerateMocks, to notify ScalaMock that along with the DAO trait, its companion object will be mocked as well.

import com.oreilly.testingscala._
import org.scalamock.annotation.{mockWithCompanion, mockObject, mock}

@mock[Artist]
@mock[Album]
@mock[Track]
@mock[Band]
@mock[JukeBox]
@mock[CompilationAlbum]
@mockWithCompanion[DAO]
@mockObject(BruceSpringsteenFactory)
class GenerateMocks

The significant change is that the annotation is no longer @mock[DAO] but @mockWithCompanion[DAO]. This lets ScalaMock know it must generate a mock with the intent that not only will the trait or class be mocked, but its corresponding companion object as well.

After calling generate-mocks in SBT, compiling the tests, running the tests, failing, and successfully implementing the production code, the end result of the subject under test will look somewhat like the following example.

package com.oreilly.testingscala

class AlbumMultipleStorageService {
   val mysqlDAO = DAO.createMySqlDAO
   val db2DAO = DAO.createDB2DAO

   def persist(album:Album) {
     mysqlDAO.persist(album)
     db2DAO.persist(album)

     album.acts.foreach{act => mysqlDAO.persist(act); db2DAO.persist(act)}
   }
}

Notice that the first two lines of AlbumMultipleStorageService are calls to the singleton companion object to retrieve the specified DAOs. When the persist method is called, it uses those DAOs to persist the albums and any acts associated with the album.

Making good examples for testing singleton objects was tough, mainly because making a call to a singleton (or static) method within another method is something that I typically stay away from—since it tightly couples two objects and makes one object completely dependent on another. My preferred modus operandi for testing is to call singleton methods outside the subject under test and inject the results.

The process of calling methods, then taking the result, and injecting them into the subject, making it decoupled and easily testable, is called inversion of control.

In the Scala world, though, there are other different and interesting ways to wire objects with one another. One such technique is the “cake pattern.” This pattern makes heavy of use of layering Scala traits. Since the traits contain the components used to build up the application, having the ability to mock singleton and companion objects may come in handy.

Mocking Functions

An interesting facet of ScalaMock is the ability to mock functions.

This can be invaluable for functions that your test has to invoke but that do real-world work you don’t want to do during a test: for instance, a function that communicates with another system over a network or performs time-consuming calculations.

 val styxAlbum: Album = new Album("Styx Album", 1945, new Band("Styx"))
 val sarahMcLachlanAlbum: Album = new Album("Sarah McLachlan Album", 1997, new Artist("Sarah", "McLachlan"))
 val billyJoelAlbum: Album = new Album("Billy Joel Album", 1977, new Artist("Billy", "Joel"))

 val albumFunction = mockFunction[Album, Int]
 albumFunction expects (styxAlbum) returning (5)
 albumFunction expects (sarahMcLachlanAlbum) returning (4)
 albumFunction expects (billyJoelAlbum) returning (5)

 ((styxAlbum :: sarahMcLachlanAlbum :: billyJoelAlbum :: Nil) map albumFunction) must be(5 :: 4 :: 5 :: Nil)

Some albums for Styx, Sarah McLachlan, and Billy Joel are assembled for this example. albumFunction is a mock function of type Function1[Album, Int], which takes in an Album and returns an Int. This function in the example is meant to represent some sort of call to a service, either local or remote, that will return the album’s rating. Mocking a function merely needs a call of mockFunction with the types that are required, in this case, Album and Int. After the declaration, expectations can then be created—in this case, that passing an Album to the function will return an Int. When the function is now plugged into a map method call, the list of albums on the left should be the list of ranks that were provided by the expectations: 5, 4, 5.

Unlike singleton objects, classes, and companion classes, no annotations are required on the GenerateMocks dummy class. So if you wish to use the regular build.sbt file as opposed to a Scala build file and don’t require concrete, final, or object mocking, having just a plain build.sbt file is perfectly fine, since mocking a function doesn’t require a call to generate-mocks.

Mocking Finals

Finals have been another bane for test-driven programmers. One reason is that abstracting a class is often a strategy for united testing, since you can override heavy non-isolated processes for something light and testable. Another reason is that most frameworks also extend classes as part of their trick to mock classes. Most test driven developers use the adapter pattern to cover up the final classes to make them friendly for testers.

The amazing ScalaMock makes mocking final classes a snap. Just mock the final class in question, add the class as an annotation to the Dummy class (in our example it is called GenerateMocks.scala), and ScalaMock will do the rest. It’s the same process, with the same results.

To prove that it works, suppose JukeBox was changed from a regular class to a final class, by simply adding final. All the tests we have written using ScalaMock would continue to pass. The following code snippet is a JukeBox that has been made into a final class.

/src/main/scala/com/oreilly/testingscala/JukeBox.scala

package com.oreilly.testingscala

final class JukeBox private (val albums:Option[List[Album]], val currentTrack:Option[Track]) {
  def this(albums:Option[List[Album]]) = this(albums, None)
  def readyToPlay = albums.isDefined
  def play = new JukeBox(albums, Some(albums.get(0).tracks.get(0)))
}

Rerunning the previous test case that mocked JukeBox shows that Jukebox is actually mocked.

class UsingScalaMockSample extends Spec with MustMatchers with MockFactory with GeneratedMockFactory {
  describe("ScalaMocks can create mocks of various structures") {

    //Omitted previous tests for brevity

    it("can also mock regular object, and along with other traits") {
      val daoMock = mock[DAO]
      //set up actual values to be used.
      val theGratefulDead: Band = mock[Band]
      val wyntonMarsalis: Artist = mock[Artist]
      val psychedelicFurs: Band = mock[Band]
      val ericClapton: Artist = mock[Artist]

      val workingmansDead = mock[Album]
      val midnightToMidnight = mock[Album]
      val wyntonAndClapton = mock[Album]

      val jukeBox = mock[JukeBox]

      //create the subject under test
      val jukeboxStorageService = new JukeboxStorageService(daoMock)

      inSequence {

        jukeBox.expects.albums returning (Some(List(workingmansDead, midnightToMidnight, wyntonAndClapton)))

        daoMock.expects.persist(workingmansDead)
        workingmansDead.expects.acts returning (List(theGratefulDead))
        daoMock.expects.persist(theGratefulDead)

        daoMock.expects.persist(midnightToMidnight)
        midnightToMidnight.expects.acts returning (List(psychedelicFurs))
        daoMock.expects.persist(psychedelicFurs)

        daoMock.expects.persist(wyntonAndClapton)
        wyntonAndClapton.expects.acts returning (List(ericClapton, wyntonMarsalis))
        daoMock.expects.persist(ericClapton)
        daoMock.expects.persist(wyntonMarsalis)
      }

      jukeboxStorageService.persist(jukeBox)
    }

    //Omitted next tests for brevity
  }
}

Even though Jukebox is final, running the test will cause no detriment to this test whatsoever.

[info] ScalaMocks can create mocks of various structures
[info] - can create a mock for a trait
[info] - can also mock regular object, and along with other traits
[info] - can mock a singleton object
[info] - can mock a companion object
[info] - can mock a function

Note

The Jukebox has no reason to be a final class: the final keyword in this example is for the purpose of demonstration.

Creating stunt doubles is a test-driven development canon. Test-driven development requires that only one class is the subject of the test, no other. All other classes and objects will need to be replaced with either a fake, a dummy, a stub, or a mock. The popular Java mocking frameworks work really well in Scala, and as seen, testing frameworks such as ScalaTest and Specs2 have sugars that make a simple process even simpler by making mocking look like an inherit part of its own package.

If the test-driven developer requires more power to mock objects like functions, Scala object, and final classes, then ScalaMock is the mocking library to use.

Given what you have learned in this chapter, you may find yourself attracted to one testing framework over another either based on the mocking syntax sugars or whether it supports ScalaMock at this time, although I anticipate that both ScalaTest and Specs2 will support ScalaMock in the future.



[4] Many functional programmers shy away from throwing exceptions, opting instead to use a type like Either to establish whether something was successful or not. This example is meant for demonstration purposes.

[5] The recipe for the mojito beverage, which Mockito is loosely named after, requires a good amount of superfine sugar.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.21.248.162