class Service1 @Inject()(service2: Service2) {
val url = service2.REDIS_URL
}
class TestService @Inject()(service1: Service1) {
def foo() => {}
}
I have the above 2 classes.
I need to test TestService.foo. Following is the code that I am trying but its not working.
class TestServiceTest extends org.scalatest.AsyncFunSuite with MockFactory {
val service1Mock = mock[Service1]
....
....
}
While initiating the test cases service2.REDIS_URL fails with null pointer error.
I am unable to find any answers in the scala mock documentation about how to properly mock services/singleton objects.
Update:
class Service2 @Inject()(){
val REDIS_URL = "some constant"
}
class Service1 @Inject()(service2: Service2){
val redisStr = service2.REDIS_URL
def getUrl = redisStr
}
class TestService @Inject()(service1: Service1){
def foo() = service1.getUrl
}
it should "test properly" in {
val mocks1 = mock[Service1]
}
This is not working
but if we change Service1 to
class Service1 @Inject()()(service2: Service2) {
def url = service2.REDIS_URL
}
it works.
But,
class Service1 @Inject()()(service2: Service2) {
def url = service2.REDIS_URL
config.useSingleServer()
.setAddress(REDIS_URL)
}
Again fails
This is due to service2 being null while the Mock is generated. This is very weird that the class is run while creating the Mock in ScalaTest and it finds service2 to be null causing NPE.
No, you cannot mock singleton objects in Scala. But I don't see any in your code. And you mock services just like any other class in Scala.
I am not sure I understand what your actual problem is, but I will try explain the best I can what I understood so far. As someone already said you have to tell your mock what calls to mock, otherwise of course it has no choice but to return null to whatever tries dereferencing it.
By mixing in
MockFactorythis means you are using themockmethod of ScalaMock. A known limitation of ScalaMock is that it does not support mocking of val fields. This is because mocks are generated using macros as anonymous subclasses of the class to mock. But the Scala compiler does not allow overriding ofvalfields in subclasses, becausevalfields are immutable.So there is no way you can mock
service1.url, as long asurlremains aval. A quick fix is converting theurlinto adef, so you can then mock the call to the methodurland that should solve your null pointer issue. Here's that idea in action:This works. No nulls here. If for some reason, you don't want to change the
urlinto adef, a better alternative is to switch tomockito-scalabecause that can mock fields as well. You don't need ScalaMock for this.If I understood correctly and your mock of
Service1is still failing with ScalaMock even after changingurltodeffor some unknown reason, then that's one more reason to switch tomockito-scala. I could not reproduce your null pointer using it. First import this:I tested
TestService.fooas follows:And it worked as expected.