In Kotlin, a variable must be initialized at declaration time, and cannot be null unless it has ? appended to the type name. So a bean reference intended to be injected by Spring would have to be declared as:
#AutoWired
var someService: SomeService? = null
The nuisance is obviously that from here on everywhere someService is used, some kind of null-safety logic has to be specified, be it ?: or a straight-up null check.
Of course we can do:
#AutoWired
var someService = new SomeService()
But that's not always possible, and the throwaway instance is just confusing.
My question is, is there anyway to tell Kotlin that this variable will be initialized and actually not be null?
You have two options.
1) use constructor injection
Constructor injection is in my opinion the best way because it clearly declares that the dependencies must be set to construct the object.
2) declare your field as lateinit
Read more on tht topic in the doc:
https://kotlinlang.org/docs/reference/properties.html
Late-Initialized Properties
Normally, properties declared as having a non-null type must be
initialized in the constructor. However, fairly often this is not
convenient. For example, properties can be initialized through
dependency injection, or in the setup method of a unit test. In this
case, you cannot supply a non-null initializer in the constructor, but
you still want to avoid null checks when referencing the property
inside the body of a class.
public class MyTest {
lateinit var subject: TestSubject
#SetUp fun setup() {
subject = TestSubject()
}
#Test fun test() {
subject.method() // dereference directly
}
}
The Spring project official recommendation is to use constructor injection.
In Kotlin it will look something like this:
#Service
class GobblinMetricsConsumer(
private val graphiteClient: GraphiteClient,
private val parserService: JsonParserService,
private val kafkaConfigurationProperties: KafkaConfigurationProperties
) {
// code will go here
}
Related
On the first screenshot you can see my test class. This class is annotated with #ExtendWith({MockitoExtension.class}) and also the tested service is annotated with #InjectMocks. On the second screenshot you can see the tested service.
Why does Mockito uses the long supplier in both cases?
Mockito uses different strategies when injecting mocks in this order:
Constructor injection
Property setter injection
Field injection
Field injection will not work in your example, since the service's fields are declared final.
Since the fields are declared final and the code snippet you showed does not have a field initializer, I assume that you have a constructor with the Supplier args. E.g.
public SomeService(Supplier<String> stringSupplier, Supplier<Long> longTimeSupplier) {
this.stringSupplier = stringSupplier;
this.longTimeSupplier = longTimeSupplier;
}
Thus Mockito will try the constructor injection, find the constructor with the two Supplier parameters and tries to resolve the arguments.
Mockito then finds the two Supplier mocks in the test, but it can not see the generic type due to type erasure. Thus Mockito sees the constructor like this:
public SomeService(Supplier stringSupplier, Supplier longTimeSupplier)
Mockito can also not decide which Supplier to use based on the parameter name, because the normal Java reflection API does not provide that information. So the name of the mocks, will not be taken into account.
There are libraries like paranamer that read the bytecode and extract the debug information to read the parameter names, but Mockito doesn't use that libs.
Thus Mockito just injects the first matching mock which is Supplier<String> stringSupplier in your case. Even your issues is related to generics, Mockito would also act the same way when you have two parameters of the same type that are not generic.
I assumed that you have a constructor that takes the two Supplier. So you can just invoke it in your test's before.
#BeforeEach
public void setup() {
service = new SomeService(stringSupplier, longSupplier);
}
If you can not access the constructor, e.g. it has package scope, you need to invoke it using reflection and set the accessible property to true
#BeforeEach
public void setup() throws Exception {
Constructor<SomeService> constructor = SomeService.class.getConstructor(Supplier.class, Supplier.class);
constructor.setAccessible(true);
service = constructor.newInstance(stringSupplier, longSupplier);
}
PS If you want to remove the final, make sure that the mocks are either named after the fields in the service longTimeSupplier vs. longSupplier or you use #Mock(name = "longTimeSupplier").
I have this test:
#RunWith(MockitoJUnitRunner.class)
public class MainClassTest {
#Mock
Dependence dependence;
#InjectMocks
MainClass mainClassTester;
}
And this test:
#Test
public void testA() {
when(dependence.getStatus()).thenReturn(true);
mainClassTester.startStatusOperation();
}
My MainClass class looks like:
public class MainClass{
private Dependence dependence = new Dependence() ;
public boolean startStatusOperation(){
boolean status = dependence.getStatus();
[...]
}
}
Im getting NullPointer in this line:
boolean status = dependence.getStatus();
Why doesn't the mock "dependence" work? This code always worked when I used #inject, but can't use in this one.
If you want to use constructor to create object instead of #Inject, you need to mock the constructor instead of just using #Mock.
#InjectMock will only inject the field which you use by #Inject. If you have any field which is set by new constructor, this will be not injected in test object if you use #InjectMock.
From http://site.mockito.org/mockito/docs/current/org/mockito/InjectMocks.html
#Documented
#Target(value=FIELD)
#Retention(value=RUNTIME)
public #interface InjectMocks
Mark a field on which injection should be performed.
Allows shorthand mock and spy injection.
Minimizes repetitive mock and spy injection.
Mockito will try to inject mocks only either by constructor injection, setter injection, or property injection in order and as described below. If any of the following strategy fail, then Mockito won't report failure; i.e. you will have to provide dependencies yourself.
Constructor injection; the biggest constructor is chosen, then arguments are resolved with mocks declared in the test only. If the object is successfully created with the constructor, then Mockito won't try the other strategies. Mockito has decided to no corrupt an object if it has a parametered constructor.
Note: If arguments can not be found, then null is passed. If non-mockable types are wanted, then constructor injection won't happen. In these cases, you will have to satisfy dependencies yourself.
Property setter injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the property name and the mock name.
Note 1: If you have properties with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching properties, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
Field injection; mocks will first be resolved by type (if a single type match injection will happen regardless of the name), then, if there is several property of the same type, by the match of the field name and the mock name.
Note 1: If you have fields with the same type (or same erasure), it's better to name all #Mock annotated fields with the matching fields, otherwise Mockito might get confused and injection won't happen.
Note 2: If #InjectMocks instance wasn't initialized before and have a no-arg constructor, then it will be initialized with this constructor.
I have a class that I mocked like this:
#Mock
private MyClass1 mockMyClass1;
Say this class looks like that:
public class MyClass1 {
#Autowired
private MyInnerClass myInnerClass;
}
When I mock MyClass1, MyInnerClass will be initialized as null. Is it possible to initialize that private field with another mock objected? I want myInnerClass to be a mock like this one:
#Mock
private MyInnerClass myInnerClass;
If I use the following code:
#InjectMocks
private MyClass1 mockMyClass1;
#Mock
private MyInnerClass myInnerClass
This will initialize the private MyInnerClass inside MyClass1 to be the mocked object, however this way mockMyClass1 is not a mock itself any more, isn't it (I'm only injecting a mocked object inside a real class, just like #Autowired will inject a real object insite it)? Could you correct my logic if I'm wrong in my understanding of #InjectMock and #Mock? Also how could I inject a mocked object inside another mocked object (without using setters/constructors)?
You are misunderstanding what a mock is.
When you are mocking MyClass1, the inner field of type MyInnerClass doesn't exist anymore for the mocked object. As such, it doesn't make sense to try to inject something into a mock.
A mock is controlled by saying what it should do when you interact with it. You stub its public methods to do what you want them to do. You give behaviour. The only default behaviour (maybe specific to Mockito) is to return null if you didn't configure the mock (but do note that it doesn't return null because some internal variable is null, it returns that because Mockito decided that that's what it should return; maybe another mocking framework decided that it should throw an exception instead, who knows?).
As an example, consider that your real class is:
class MyClass1 {
private MyInnerClass myInnerClass;
public MyInnerClass getMyInnerClass() {
return myInnerClass;
}
}
Now consider mock a mock of that class. If you call mock.getMyInnerClass(), it is not the real method that is going to be called. What it will return is not the value of myInnerClass. It will return null, or if you have stubbed that method with
when(mock.getMyInnerClass()).thenReturn(something);
then it will return something.
So to answer your question: you can't do that because that's not how mocks work.
You shouldn't really use InjectMocks annotation at all (to see why, you can read this article).
You could just implement an Autowired constructor for MyClass1 instead of Autowired fields. Then you could simply pass your MyInnerClass mock reference as a constructor parameter.
I am trying to introduce Scala into my Android project, which uses Guice for DI. For Guide to work, I need to add the #Inject annotation to the constructor I would like Guice to use. In my case I created a Scala class and I need to use it in my Java code.
scala:
class scalaClass1(a: String) {
var myA = a
#Inject
def this() = { this("test") }
}
This looks alright, correct? But in another case the constructor does not have any parameters, so I tried
scala:
class scalaClass2() {
var myA: String = null
#Inject
def this() = { this() }
}
And I got an syntax error. Something like recursive definition. Then I tried this:
scala:
class scalaClass2() {
var myA: String = null
#Inject
def scalaClass2() = { this }
}
The code compiled and the app works well on my phone. I have no idea why. I browsed in google, but I could not find any definition/explanation about having a method that has the same name as the class. Why this works? Is there any better solution to my problem?
If you need to to apply #Inject to a constructor without parameters you can use this:
class scalaClass2 #Inject () {
// whatever
}
Note the mandatory empty parentheses. You need them to apply an annotation on the primary constructor. But in this particular case you don't even need #Inject; see below.
In your second example (when you define def this() = { this() }) you are getting an error because you can't define multiple constructors with the same signature, and that's exactly what you are doing - you define primary constructor without parameters and immediately you define secondary constructor, again without parameters.
And in the third example you're really defining a method named scalaClass2 which returns this. It is perfectly valid, but it is not a constructor. As far as I remember, Guice does not need #Inject annotation on parameterless constructor when it is the only constructor in the class, so you can inject scalaClass2 or ask it from Guice, who will create it for you. But you don't really need scalaClass2 method; Guice may call it as a part of method injection procedure but it won't do anything.
Firstly, according to convention class names should start with upper case and methods with lower. But if we would not follow them I would say it is not safe.
Consider having a companion object to the class with apply method defined.
class Person(val name: String, val age: Int)
object Person {
def apply(name: String, age: Int) = new Person(name, age) }
and then create a method with same name and list parameters:
def Person(lastName: String, score: Int): String = s"${lastName} got ${score} points in last game"
Now if you want to make use of object apply method you cannot do it in regular way:
Person("McKenzie", 1000)
will yield McKenzie got 1000 points in last game
I'm trying to use Scala as part of an existing Java application and now I run into an issue with dependencies injected with a setter method (no DI frameworks in this part of code). How is this handled in a Scala way?
In Scala both val and var require to be initialized when declared but I can't do that, since the Java setters inject objects that implement a certain interface and interfaces are abstract and can not be instantiated.
class ScalaLogic {
var service // How to initialize?
def setService (srv: OutputService) = {
service = srv
}
Is there a way to initialize the var service so that I can later assign a dependency into it? It should be lexically scoped to be visible in the whole class.
You can initialize to a default (null) using an underscore.
class ScalaLogic {
var service: OutputService = _
def setService (srv: OutputService) = {
service = srv
}
}
The nice thing about the underscore (as opposed to just using null) is that it works with both primitives and objects, so parameterized classes work like this:
class ScalaLogic[T] {
var service: T = _
def setService (srv: T) = {
service = srv
}
}
One of the many meanings of the underscore is to mark a variable as uninitialized. So if you want an uninitialized field, initialize it with _ .
To have getters and setters for a field annotate it with #BeanProperty. The compiler will generate the Java-Style getter and setter for you.
import reflect.BeanProperty
class ScalaLogic {
#BeanProperty
var service: OutputService = _
}
By the way, the canonical reference to Dependency Injection in Scala is the summary by Jonas Bonér. This article does not cover setter-based injection, though, if I recall correctly.
Try using class Option. This is the moral equivalent of using null in Java. Declare the service like so:
var service: Option[MyInterface] = None
and use
service.get()
or pattern matching
service match {
case None => ...
case Some[MyInterface] => ...
}