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 separateMockLoginServiceclass, 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
LoginServiceshould 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
LoginServiceinstance 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
MockitoSugarimport 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 |