Mockito for Objects in Scala - scala

I'm using Scala 2.10, specs2 and Mockito. I want to mock scala.io.Source.fromURL(). The issue seems to be fromURL() is a function in io.Source's object.
val m = mock[io.Source]
m.fromURL returns io.Source.fromString("Some random string.")
It's a pretty straightforward mock in an Unit test. Why isn't it working?
Thanks!

Instead of mocking it, you could try spying it as follows:
val m = spy(io.Source)
Or you could mock it as follows:
val m = mock[io.Source.type]
But then how are you using Source in the class you are testing? If you had an example class like so:
class MyClass{
def foo = {
io.Source.doSomething //I know doSomething is not on Source, call not important
}
}
Then in order to take advantage of mocking/spying, you'd have to structure your class like so:
class MyClass{
val source = io.Source
def foo = {
source.doSomething
}
}
And then your test would have to look something like this:
val mockSource = mock[io.Source.type]
val toTest = new MyClass{
override val source = mockSource
}
In the Java world, static methods are the bane of mocking. In the Scala world, calls to objects can also be troublesome to deal with for unit tests. But if you follow the code above, you should be able to properly mock out an object based dependency in your class.

Good news! With the latest 1.16 release of mockito-scala, you can now mock scala objects.
To enable withObjectMocked feature, it is mandatory to create the file src/test/resources/mockito-extensions/org.mockito.plugins.MockMaker containing a single line:
mock-maker-inline
Example:
object FooObject {
def simpleMethod: String = "not mocked!"
}
"mock" should {
"stub an object method" in {
FooObject.simpleMethod shouldBe "not mocked!"
withObjectMocked[FooObject.type] {
FooObject.simpleMethod returns "mocked!"
//or
when(FooObject.simpleMethod) thenReturn "mocked!"
FooObject.simpleMethod shouldBe "mocked!"
}
FooObject.simpleMethod shouldBe "not mocked!"
}
}
See: https://github.com/mockito/mockito-scala#mocking-scala-object

Years later, above answer doesn't work as others have pointed out.
And you cannot mock the scala.io.Source object.
Can I mock final / private methods or classes? This is not supported, as mocks generated with macros are implemented as subclasses of the type to mock. So private and final methods cannot be overridden. You may want to try using an adapter or façade in your code to make it testable. It is better to test against a trait/interface instead of a concrete implementation. There are libraries that support this kind of mocking, such as PowerMock. Be aware that this kind of mocking involves Bytecode manipulation, which has the risk that your test double diverges from the actual implementation.
So what I did is an work around to abstract out scala.io.Source.fromUrl() as a function argument and pass in mocked function in tests.
// original func
def aFuncThatUsesSource() = {
val source = scala.io.Source("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
// test friendly func that accepts `scala.io.Source.fromURL` as arg
def aTestFriendlyFunc(makeApiCall: String => BufferedSource) = {
val source = makeApiCall("127.0.0.1:8080/...")
val result = source.mkString
Try(source.close())
result
}
....
// test spec
def testyMcTesterson = () => {
val makeApiCall = mockFunction[String, BufferedSource]
makeApiCall.expects("something...")
.returns( new BufferedSource(new ByteArrayInputStream("returns something".getBytes)) )
aTestFriendlyFunc(makeApiCall) shouldEqual "returns something"
}

Related

How do I mock a Scala Companion Object with EASYMOCK on Scala 3? [duplicate]

This question already has an answer here:
How to mock an Object in Scala
(1 answer)
Closed 7 months ago.
I have the following code...
class CoreDataSource {
def getConnection = {
println("Getting the connection")
CoreDataSource.getConnection
}
}
object CoreDataSource {
def getConnection: Option[Connection] = {
getDataSource.get.getConnection
}
def getDataSource: Option[DataSource] = {
...
config = new HikariConfig // This has side effects and can't run
...
val pool : DataSource = new HikariDataSource(config) // This has side effects and can't run
...
Some(pool)
}
}
I am trying to mock out the creation of the HikariDataSource and HikariConfig. I tried this...
class CoreDataSourceSpec extends AnyFunSpec with EasyMockSugar {
describe("Core Data Source") {
it("Do something") {
val cdsMock = mock[CoreDataSource.type]
...
}
}
}
But I get
Cannot subclass final class ....CoreDataSource$
What is the proper way to Mock out a companion object using EasyMock
You don't.
Companion object should only perform pure computations (at least don't contain state) which don't require mocking. Most of the time it's purpose is to store factories and instances of type classes (implicits/givens) for your type.
If you store a mutable state (e.g. connection to the database) in companion you messed up. If you have a Java background, think this way: would you mock static methods of a class? (If you're drifting towards PowerMockito you should reconsider your life choices).
Your example shows that you want to store the connection somewhere - storing it in companion is basically global, shared, mutable state which is universally a bad idea, no matter the background.
Create factory of CoreDataSource in its companion, then pass around CoreDataSource instance directly. No issue with mocking that in your tests.
class CoreDataSource(dataSource: DataSource) {
def getConnection: Connection =
dataSource.getConnection
}
object CoreDataSource {
def createHikari(config: HikariConfig): CoreDataSource =
new CoreDataSource(new HikariDataSource(config))
}
// in test:
val dataSource = mock[DataSource]
val coreDataSource = new CoreDataSource(dataSource)
// then mock dataSource.getConnection
Doing it another way requires solving the hard problem that you have 0 reasons to have in the first place. If this companion object is not your but someone else and you cannot rewrite it - wrap it in your own code that you can control and mock easily.
EDIT. In case you are using something like Google Cloud... it still doesn't make sense to store everything in companion and mock it.
// functionality
class MyService(
connection: Connection
) {
def someFunctionality(arg: Arg): Result = ...
}
// in test
// given
val connection = mock[Connection] // mocking DB sounds like a bad idea but whatever
val myService = new MyService(connection)
// when
myService.someFunctionality(arg)
// then
// assertions
// adapter for Google Cloud, other cloud solutions should be similar
class MyFunction extends HttpFunction {
private val config = ...
private val coreDataSource = CoreDataSource.hikari(config)
private val connection = coreDataSource.getConnection
private val myService = new MyService(connection)
override def service(request: HttpRequest, response: HttpResponse): Unit = {
// extract data from request, then
val result = myService.someFunctionality(arg)
// then send result in response
}
}
And if you needed to cache these private vals - what you are caching is NOT related to business logic at all, it merely wires things together, like main in Java which is never tested, nor require testing.
So you could implement it like:
class MyFunction extends HttpFunction {
override def service(request: HttpRequest, response: HttpResponse): Unit = {
// extract data from request, then
val result = MyFunction.myService.someFunctionality(arg)
// then send result in response
}
}
object MyFunction {
// dependency injection and initialization
private val config = ...
private val coreDataSource = CoreDataSource.hikari(config)
private val connection = coreDataSource.getConnection
val myService = new MyService(connection)
}
where wrapper MyFunction is NOT tested, but MyService which does all the job is easily testable.
You should definitely read more about the language, beside the fact that the other answer mentioned (which is you should only contain pure class-level functionalities in the companion object), you cannot do it. Why? Because companion objects are singleton objects of a final class, which can access private states of the companion class itself and vice versa (think of it kind of like static data of the class).
The thing is, companion object actually is an object of a final class (which if you want, I can provide more details about them). Final classes cannot be mocked, simply because they are "final", and their behavior cannot be changed (even by its subclasses). And mocking is all about mocking a class behavior, not an object's behavior.

Test if a method was called without providing parameters

I have the following code:
class MyClass {
def someMethods(): Unit = {
val result1 = method1()
val result2 = method2(result)
}
}
No I want to test if method1 and method2 are called, when I run someMethod.
class TestMyClass {
#Test
def testSomeMethods(): Unit = {
val myClass = new MyClass()
val myClassSpy = Mockito.spy(myClass)
myClassSpy.someMethods()
verify(myClassSpy).method1()
}
}
For method1 this is working, but method2 needs a parameter, that is provided by method1.
Can I not just do something like assertTrue(method2.called)?
Because I do not want to check the result of the methods, I just want to know if they were called.
Hmm, using a spy for that is already a smell, you shouldn't be testing internals of your class like that.
In any case you could do Mockito.verify(myClassSpy).method2(Mockito.any()) and that would do the trick, but I'd seriously review your design and the motivation behind this test as it really feels like the wrong approach.

Mock new object creation in Scala

I want to write unit test for below scala class.
In the below implementation, QueryConfig is final case class.
class RampGenerator {
def createProfile(queryConfig: QueryConfig): String = {
new BaseQuery(queryConfig).pushToService().getId
}
}
The unit test I have written is this
#RunWith(classOf[JUnitRunner])
class RampGeneratorTest extends FlatSpec with Matchers {
"createProfile" must "succeed" in {
val rampGenerator = new RampGenerator()
val queryConfig = QueryConfig("name", "account", “role")
val baseQuery = mock(classOf[BaseQuery])
val profile = mock(classOf[Profile])
when(new BaseQuery(queryConfig)).thenReturn(baseQuery)
when(baseQuery.pushToService()).thenReturn(profile)
when(profile.getId).thenReturn("1234")
val id = rampGenerator.createProfile(queryConfig)
assert(id.equals("1234"))
}
}
Currently it gives below exception, which is expected, since I don't have mocked class used in when. How do I mock the new instance creation?
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
There are two options:
Use powermockito to mock the constructor (see this question for details)
Externalize object creation
A bit more on the second option - this is actually a testing technique that helps in a variety of situations (a couple of examples: yours, creating akka actors and asserting on hierarchies) - so it might be useful to just have it in the "toolbox".
In your case it'll look something like this:
class RampGenerator(queryFactory: QueryFactory) {
def createProfile(queryConfig: QueryConfig) = queryFactory.buildQuery(queryConfig).pushToService().getId()
}
class QueryFactory() {
def buildQuery(queryConfig: QueryConfig): BaseQuery = ...
}
#RunWith(classOf[JUnitRunner])
class RampGeneratorTest extends FlatSpec with Matchers {
"createProfile" must "succeed" in {
val rampGenerator = new RampGenerator()
val queryConfig = QueryConfig("name", "account", “role")
val queryFactory = mock(classOf[QueryFactory])
val profile = mock(classOf[Profile])
val baseQuery = mock(classOf[BaseQuery])
when(queryFactory.buildQuery(queryConfig)).thenReturn(baseQuery)
when(baseQuery.pushToService()).thenReturn(profile)
when(profile.getId).thenReturn("1234")
val id = rampGenerator.createProfile(queryConfig)
assert(id.equals("1234"))
}
}
Please note query factory does not have to be a separate factory class/hierarchy of classes (and certainly does not require something as heavyweight as abstract factory pattern - although you can use it). In particular, my initial version was just using queryFactory: QueryConfig => BaseQuery function, but mockito cannot mock functions...
If you prefer to inject factory method directly (via function), Scalamock has support for mocking functions

Scala mocking trait that is extended by another trait

I am trying to test
trait Name extends Helper {
def name() = {
var s = getSystem()
s.name()
}
}
where all I want to do is make sure that the "s.name()" method is invoked once by mocking an instance of s, which is a System.
Helper is defined as so:
trait Helper {
def getSystem() : System = {
systemGetter.get()
}
}
As of now, my NameSpec looks something like:
class NameSpec extends FlatSpec with Matchers with MockitoSugar {
class NameImpl extends Name
var toTest = new NameImpl
val mockSystem = mock[System]
it should "call s.name() once" in {
when(getSystem() is invoked, return a mockSystem)
toTest.name()
// Verify that mockSystem.name() happened only once
}
}
What I'm confused about is how to return a mock System in toTest.name() when it calls getSystem() so that I can verify that the system calls s.name() only once. I could easily mock this System if it were a parameter to the name() method in Name trait, so I guess I don't know how to "inject" a mockSystem to be used instead of a real system when that method is invoked.
Unfortunately your code is not compilable and thus is obviously an inadequate representation of what you really have. Particularly it is not clear how the Helper really gets an object of type System. I think that in the real code you should mock the systemGetter, that I suppose is somehow injected into the objects implementing Helper trait, to return your mockSystem. However it is hard to show you a valid example of that basing on the code you provided. If for some reason this is not what you can do, there are a few more avenues.
You seem to use something like Cake pattern around Helper and its inheritance. If so, you can use a class instead of NameImpl to inject System:
class NameWithInjectedSystem(val system: System) extends Name {
override def getSystem(): System = system
}
it should "call s.name() once" in {
val mockSystem = mock[System]
val nameToTest = new NameWithInjectedSystem(mockSystem)
val mockName = "Mock name"
when(mockSystem.name()).thenReturn(mockName)
val actual = nameToTest.name()
actual should === (mockName)
verify(mockSystem, times(1)).name()
}
Finally you can mock even nameToTest object itself but this is not the way I'd suggest because it binds test to much more implementation details than you should want:
it should "call s.name() once" in {
val mockSystem = mock[System]
val nameToTest = mock[NameImpl]
when(nameToTest.getSystem()).thenReturn(mockSystem)
when(nameToTest.name()).thenCallRealMethod()
val mockName = "Mock name"
when(mockSystem.name()).thenReturn(mockName)
val actual = nameToTest.name()
actual should ===(mockName)
verify(mockSystem, times(1)).name()
}
Note how you must call thenCallRealMethod for the .name() call and so you should do for all the calls inside the name or the test will not work.

Mocking scala object

I am using mockito and trying to mock a scala object.
object Sample { }
//test
class SomeTest extends Specification with ScalaTest with Mockito {
"mocking should succeed" in {
val mockedSample = mock[Sample]
}
}
This gives me two compilation errors.
error: Not found type Sample
error: could not find implicit value for parameter m:
scala.reflect.ClassManifest[<error>]
If I change Sample from object to class it works.
Is is possible to mock scala objects with mockito? If yes how?
As written, your Sample is a pure singleton. Its type is its own and there is only one member of that type, period. Scala objects can extend another class (possibly abstract, if it supplies the necessary definitions to make it a concrete) and traits. Doing that gives it a type identity that includes those ancestors.
I don't know what Mockito is really doing, but to my mind, what you're asking for is strictly at odds with what a Scala object is.
Keep in mind that you can mock the methods of an object if you lift them to functions.
case class Person(name: String)
object Person {
def listToJson(lp: List[Person]) = "some actual implementation"
}
class ClassUnderTest(listToJson: (List[Person]) => String = Person.listToJson(_)) {
def testIt(lp: List[Person]) = listToJson(lp)
}
import org.specs._
import org.specs.mock.Mockito
import org.mockito.Matchers._
class ASpec extends Specification with Mockito {
"a thing" should {
"do whatever" in {
val m = mock[(List[Person]) => String]
val subject = new ClassUnderTest(m)
m(Nil) returns "mocked!"
subject.testIt(Nil) must_== "mocked! (this will fail on purpose)"
}
}
}
Here I'm not mocking the object Person, but the method on it (which is probably what the OP was intending).
The test result shows the mocking works:
[info] == ASpec ==
[error] x a thing should
[error] x do whatever
[error] 'mocked![]' is not equal to 'mocked![ (this will fail on purpose)]' (ASpec.scala:21)
[info] == ASpec ==
Meanwhile, the production-time usage of the ClassUnderTest is simply new ClassUnderTest due to the injected function being a default argument.
Since version 1.16.0 of mockito-scala it is possible to mock Scala objects, you can check the docs here, but this is an example of how it would look like.
object FooObject {
def simpleMethod: String = "not mocked!"
}
"mock" should {
"stub an object method" in {
FooObject.simpleMethod shouldBe "not mocked!"
withObjectMocked[FooObject.type] {
FooObject.simpleMethod returns "mocked!"
//or
when(FooObject.simpleMethod) thenReturn "mocked!"
FooObject.simpleMethod shouldBe "mocked!"
}
FooObject.simpleMethod shouldBe "not mocked!"
}
}
I've recently released ScalaMock, a mocking library for Scala that can, among other things, mock singleton (and companion) objects.