Problem: You want to use a mock object framework in your ScalaTest tests, such as Mockito.
Solution
ScalaTest offers support for the following mock testing frameworks:
Because the support for each framework is similar, let’s take a look at using Mockito.
Before starting, imagine that you have a login web service for your application, and rather than call the real web service during your tests, you just want to mock one up.
In your application you have “login service” code in a file named src/main/scala/tests/LoginService.scala, which looks like this:
package tests // a very simple User class case class User(name: String) // a LoginService must have a 'login' method trait LoginService { def login(name: String, password: String): Option[User] } // the code for our real/live LoginService class RealLoginService extends LoginService { // implementation here ... }
Notice that there’s a LoginService
trait, and the RealLoginService
implements that trait. By following this pattern, you can use Mockito to “mock” your LoginService
trait in your unit tests.
The following code shows how to create and use a mock LoginService
using Mockito and ScalaTest:
package tests import org.scalatest.FunSuite import org.scalatest.BeforeAndAfter import org.scalatest.mockito.MockitoSugar import org.mockito.Mockito._ class LoginServiceTests extends FunSuite with BeforeAndAfter with MockitoSugar { test ("test login service") { // (1) init val service = mock[LoginService] // (2) setup: when someone logs in as "johndoe", the service should work; // when they try to log in as "joehacker", it should fail. when(service.login("johndoe", "secret")).thenReturn(Some(User("johndoe"))) when(service.login("joehacker", "secret")).thenReturn(None) // (3) access the service val johndoe = service.login("johndoe", "secret") val joehacker = service.login("joehacker", "secret") // (4) verify the results assert(johndoe.get == User("johndoe")) assert(joehacker == None) } }
Here’s a quick description of the code:
- In the “init” step, you create a mock version of the
LoginService
. Notice that this mocks a a trait that doesn’t have an implementation. Because you can do this, you don’t have to write a separateMockLoginService
class, which is nice. (You also don’t have to access Test or Production versions of the “real” login service, which would slow down your unit tests.) - In the “setup” portion of the code, you work with Mockito to define how the mock
LoginService
should respond when it’s given two sets of data. When “johndoe” logs in, the mock login service should return aSome(User(“johndoe”))
instance, and when “joehacker” attempts to log in, it should return aNone
. - In the “access” portion of the code, you write the code just like you would normally in your application. You call the
LoginService
instance with some data, and get objects in return. - In the “verify” portion of the code, you verify that you received the data you expected from your login service.
In more real-world tests, you’d do things slightly differently. First, you’d use a more robust User
class. Second, you’d take the objects that are received from the LoginService
and attempt to do more things with them. There isn’t much value in testing a mock LoginService
by itself, but because this mock service lets you test the next steps in your application, a mock service becomes a very useful thing.
This example is just intended to get you started in the right direction. The important part of the test is that you got a User
object back from the LoginService
, just as though you had called a real, live, production login service.
Note: The
MockitoSugar
import statement apparently changed since I originally wrote this article. I updated the source code here, and I hope it now includes the correct import. See the comment in the Comments section below for the old and new import statement.
Steps to using Mockito
To use Mockito like this in a ScalaTest project, the first step is to include the Mockito JAR file in your project. Assuming you’re using SBT, either add the Mockito JAR file to your project’s lib directory, or add Mockito as a dependency in your build.sbt file. With ScalaTest 1.9.1, this is the correct line to add to your build.sbt file:
libraryDependencies += "org.mockito" % "mockito-all" % "1.8.4"
The next step is to add the necessary imports to your unit test classes. These were shown in the example, and are repeated here:
import org.scalatest.mockito.MockitoSugar import org.mockito.Mockito._
Next, mix the MockitoSugar
trait into your test class:
class PizzaTests extends FunSuite with BeforeAndAfter with MockitoSugar {
Once you have these configuration steps out of the way, you can begin creating mock objects in your ScalaTest tests with Mockito.
See Also
There are many more ways to use Mockito and other mock object frameworks in your ScalaTest tests. These links will help you get started:
- This link on the ScalaTest website shows many ScalaMock, EasyMock, JMock, and Mockito examples: http://www.scalatest.org/user_guide/testing_with_mock_objects
- The Mockito website has many more examples: https://code.google.com/p/mockito/
this post is sponsored by my books: | |||
#1 New Release |
FP Best Seller |
Learn Scala 3 |
Learn FP Fast |