SCALA Mocking





5.00/5 (1 vote)
Last time we looked at writing unit tests for our code, where we looked at using ScalaTest. This time we will be looking at mocking.
Last time we looked at writing unit tests for our code, where we looked at using ScalaTest. This time we will be looking at mocking.
In .NET there are several choices available that I like (and a couple that I don’t), such as :
- Moq
- FakeItEasy
- RhinoMocks (this is one I am not keen on)
I personally am most familiar with Moq, so when I started looking at JVM based mocking frameworks I kind of wanted one that used roughly the same syntax as the ones that I had used in .NET land.
There are several choices available that I think are quite nicely, namely :
- ScalaMock
- EasyMock
- JMock
- Mockito
Which all play nicely with ScalaTest (which I am sure you are all very pleased to here).
So with that list what did I decide upon. I personally opted for Mockito, as I liked the syntax the best, that is not to say the others are not fine and dandy, it is just that I personally liked Mockito and it seemed to have good documentation and favorable Google search results, so Mockito it is.
So for the rest of this post I will talk about how to use Mockito to write our mocks. I will be used Mockito along side ScalaTest which we looked at last time.
SBT Requirements
As with most of the previous posts you will need to grab the libraries using SBT. As such your SBT file will need to use the following:
libraryDependencies ++= Seq( "org.mockito" % "mockito-core" % "1.8.5", "org.scalatest" %% "scalatest" % "2.2.5" % "test" )
Our First Example
So with all that stated above. Lets have a look at a simple example. This trivial example mocks out a java.util.ArrayList[String]
. And also sets up a few verifications
class FlatSpec_Mocking_Tests extends FlatSpec with Matchers with MockitoSugar { "Testing using Mockito " should "be easy" in { //mock creation val mockedList = mock[java.util.ArrayList[String]] //using mock object mockedList.add("one"); mockedList.clear //verification verify(mockedList).add("one") verify(mockedList).clear } }
One thing you may notice straight away is how the F*k am I able to mock a ArrayList[T], which is a class which is not abstract by the way. This is pretty cool.
Stubbing
Using Mockito we can also stub out things just as you would expect with any 1/2 decent mocking framework. Here is an example where we try and mock out a simple trait.
import java.util.Date import org.scalatest._ import org.scalatest.mock._ import org.mockito.Mockito._ trait DumbFormatter { def formatWithDataTimePrefix(inputString : String, date : Date) : String = { s"date : $date : $inputString" } def getDate() : String = { new Date().toString } } class FlatSpec_Mocking_Tests extends FlatSpec with Matchers with MockitoSugar { "Stubbing using Mockito " should "be easy" in { var mockDumbFormatter = mock[DumbFormatter] when(mockDumbFormatter.getDate()).thenReturn("01/01/2015") assert("01/01/2015" === mockDumbFormatter.getDate()) } }
It can be seen above that it is quite easy to mock a trait. You can also see how we stub the mock out using the Mockito functions
- when
- thenReturn
Return Values
We just saw an example above of how to use the “thenReturn
” Mockito function, which is what you would use to setup your return value. If you want a dynamic return value this could quite easily call some other function which deals with creating the return values. Kind of a return value factory method.
Argument Matching
Mockito comes with something that allows you to match against any argument value. It also comes with regex matchers, and allows you to write custom matchers if the ones out of the box don’t quite fit your needs.
Here is an example of writing a mock where we use the standard argument matchers:
import java.util.Date import org.scalatest._ import org.scalatest.mock._ import org.mockito.Mockito._ import org.mockito.Matchers._ trait DumbFormatter { def formatWithDataTimePrefix(inputString : String, date : Date) : String = { s"date : $date : $inputString" } def getDate() : String = { new Date().toString } } class FlatSpec_Mocking_Tests extends FlatSpec with Matchers with MockitoSugar { "Stubbing using Mockito " should "be easy" in { var mockDumbFormatter = mock[DumbFormatter] when(mockDumbFormatter.formatWithDataTimePrefix(anyString(),any[Date]())).thenReturn("01/01/2015 Something") assert("01/01/2015 Something" === mockDumbFormatter.formatWithDataTimePrefix("blah blah blah", new Date())) } }
Exceptions
To throw exceptions with Mockito we simply need to use the “thenThrow(….)
function. Here is how.
import java.util.Date import org.scalatest._ import org.scalatest.mock._ import org.mockito.Mockito._ import org.mockito.Matchers._ trait DumbFormatter { def formatWithDataTimePrefix(inputString : String, date : Date) : String = { s"date : $date : $inputString" } def getDate() : String = { new Date().toString } } class FlatSpec_Mocking_Tests extends FlatSpec with Matchers with MockitoSugar { "Stubbing using Mockito " should "be easy" in { var mockDumbFormatter = mock[DumbFormatter] when(mockDumbFormatter.formatWithDataTimePrefix(anyString(),any[Date]())) .thenThrow(new RuntimeException()) //use the ScalaTest intercept to test for exceptions intercept[RuntimeException] { mockDumbFormatter.formatWithDataTimePrefix("blah blah blah", new Date()) } } }
See how we also have to use the ScalaTest “intercept” for the actually testing
CallBacks
Callbacks are useful when you want to see what a method was called with and then you can make informed decisions about what you could possibly return.
Here is how you do callbacks in Mockito, note the use of the “thenAnswer
” function, and how we use an anonymous Answer
object.
import java.util.Date import org.mockito.invocation.InvocationOnMock import org.mockito.stubbing.Answer import org.scalatest._ import org.scalatest.mock._ import org.mockito.Mockito._ import org.mockito.Matchers._ trait DumbFormatter { def formatWithDataTimePrefix(inputString : String, date : Date) : String = { s"date : $date : $inputString" } def getDate() : String = { new Date().toString } } class FlatSpec_Mocking_Tests extends FlatSpec with Matchers with MockitoSugar { "Stubbing using Mockito " should "be easy" in { var mockDumbFormatter = mock[DumbFormatter] when(mockDumbFormatter.formatWithDataTimePrefix(anyString(),any[Date]())) .thenAnswer(new Answer[String] { override def answer(invocation: InvocationOnMock): String = { val result = "called back nicely sir" println(result) result } }) assert("called back nicely sir" === mockDumbFormatter.formatWithDataTimePrefix("blah blah blah", new Date())) } }
Verification
The last thing I wanted to talk about was verification. Which may include verifying functions got called, and were called the right number of times.
Here is a simple example of this:
import java.util.Date import org.mockito.invocation.InvocationOnMock import org.mockito.stubbing.Answer import org.scalatest._ import org.scalatest.mock._ import org.mockito.Mockito._ import org.mockito.Matchers._ trait DumbFormatter { def formatWithDataTimePrefix(inputString : String, date : Date) : String = { s"date : $date : $inputString" } def getDate() : String = { new Date().toString } } class FlatSpec_Mocking_Tests extends FlatSpec with Matchers with MockitoSugar { "Stubbing using Mockito " should "be easy" in { var mockDumbFormatter = mock[DumbFormatter] when(mockDumbFormatter.formatWithDataTimePrefix(anyString(),any[Date]())) .thenReturn("someString") val theDate = new Date() val theResult = mockDumbFormatter.formatWithDataTimePrefix("blah blah blah", theDate) val theResult2 = mockDumbFormatter.formatWithDataTimePrefix("no no no", theDate) verify(mockDumbFormatter, atLeastOnce()).formatWithDataTimePrefix("blah blah blah", theDate) verify(mockDumbFormatter, times(1)).formatWithDataTimePrefix("no no no", theDate) } }
Further Reading
You can read more about how to use Mockito from the docs : https://docs.google.com/document/d/15mJ2Qrldx-J14ubTEnBj7nYN2FB8ap7xOn8GRAi24_A/edit
End Of The Line
Personally my quest goes on, I am going to keep going until I consider myself good at Scala (which probably means I know nothing).
Anyway behind the scenes I will be studying more and more stuff about how to get myself to that point. As such I guess it is only natural that I may post some more stuff about Scala in the future.
But for now this it it, this is the end of the line for this brief series of posts on Scala. I hope you have all enjoyed the posts, and if you have please feel free to leave a comment, they are always appreciated.