How to avoid NPEs from default parameters in mocked classes? - kotlin

Here's a simplified version of what I want to test with Mockito:
class UnderTest {
fun doSomething() {
foo.doAnything()
}
}
class Foo {
fun doAnything(bar: Bar = Bar())
}
class TestUnderTest {
#Mock
var underTest: UnderTest
#Test
fun testDoSomething() {
underTest.doSomething() // Causes NPE
}
}
UnderTest is being tested. Its dependencies, like foo, are mocked. However, when my tests call UnderTest.doSomething(), it crashes. doSomething() calls Foo.doAnything(), letting it fill in the null parameter with the default - and the code that runs in that default parameter initialization is outside of the control of my test, as it's inside the static, synthetic method created for the byte code.
Is there a magical Mockito solution to get around this very situation? If so, I would love to hear it. Otherwise, I believe the options I have are:
To use PowerMock or Mockk to be able to mock things Mockito can't
To change Foo to have two doAnything() methods; one would have zero parameters, would call Bar() and pass it to the other.
To change Foo.doAnything() to accept a nullable parameter, then to have the body of the function call Bar() and use it.

Related

Verifying method call with enum in Kotlin

I'm trying to verify that a method is called with a given argument. That argument is a non-nullable enum type. So I get the exception eq(SomeEnum.foo) must not be null. Here is a sample what I'm trying to do:
enum class SomeEnum {
foo, bar
}
open class MyClass {
fun doSomething() {
magic(SomeEnum.foo)
}
internal fun magic(whatever: SomeEnum) {}
}
#Test
fun mockitoBug() {
val sut = spy(MyClass())
sut.doSomething()
verify(sut).magic(eq(SomeEnum.foo))
}
Capturing does not work too. What can I do or is that really a bug as I assume?
Because Mockito was designed for Java, it doesn't play well with Kotlin's null checks. A good solution is to use the mockito-kotlin extensions library: https://github.com/mockito/mockito-kotlin
It includes Kotlin versions of the matchers that won't return null. Add a dependency on mockito-kotlin and just make sure to import the Kotlin versions instead of the Java ones.

Dagger Dependency Injection in main function

I am calling a function in a class S3FileOperationsAdapter from the main function in my kotlin code. I am injecting the class S3FileOperationsAdapter in the main function file. So it looks like
class Runner {
#set:Inject
lateinit var s3FileOperationsAdapter: S3FileOperationsAdapter
fun main(args: Array<String>) {
s3FileOperationsAdapter.readFunction()
}
}
Now the issue is:
When I try to run the above code, I get the error Error: Main method is not static in class com.amazon.bram.sim.BatchJobRunner, please define the main method as:. This is understandable.
And we can only make a static function within an object in kotlin. So upon doing that, I cannot Inject the dependency, because Dagger does not support injection into Kotlin objects. So it feels like a deadlock.
My question is, I want to inject the dependency in this file anyhow so that I can call the respective function. And I am calling this function from the "fun main()" in kotlin. How can I achieve this? Has anyone ever faced this before?
In order to inject anything in Dagger, you must first create an instance of your component. Since no code at all will run before fun main(), this needs to be done during main itself (or in a field initializer).
After creating an instance of the component, you can ask it for an instance of S3FileOperationsAdapter directly.
fun main(args: Array<String>) {
// Create the component.
val component = DaggerMyComponent.create()
// or use the Component.Builder or Component.Factory you defined for MyComponent.
// Get an object from the component.
// This method should be defined in your component interface.
val adapter = component.s3FileOperationsAdapter()
// Use the object.
adapter.readFunction()
}
If your actual code is more complicated, with multiple injected objects and a longer main() function, this may be a bit unwieldy. In that case, you can extract your current main() into its own class and let Dagger provide that class in main().

Kotlintest extensions providing information back to the test

JUnit 5 has a neat extensions functionality which is not compatible with kotlintest even if it runs on JUnit framework. While the simple use cases in which we just need to log something can be handled by the TestListener, we cannot handle more advanced cases. In particular, how to interact with the extension? Ideally, I would like to get a hold of the extension so I could query it.
In JUnit5 it would be (one of the options anyway)
#ExtendWith(MyExtension.class)
class Something() {
#MyAnnotation
MyType myType;
#Test
void doSomething() {
myType.doSomething();
}
}
In JUnit4 it would be even simpler
#Rule
MyRule myRule;
#Test
void fun() {
myRule.something();
}
Of course, there is a SpringExtension but it does the reflective instantiation of the class.
Is there any way to do it easier?
You can keep a reference to an extension/listener before passing it to the overriden function.
For example:
val myListener = MyKotlinTestListener()
val myOtherListener = MyOtherKotlinTestListener()
override fun listeners() = listOf(myListener, myOtherListener)
This way you can do what you want in your tests with that reference available
test("MyTest") {
myListener.executeX()
}
The same goes if you're using an extension of any sort.
They'll still be executed as part of KotlinTest's lifecycle!

Kotlin compiler issue with overriding of Java final function in Kotlin

I’m dealing with following issue with Kotlin/Java Compiler.
Imagine following scenario: let First be a Java class with a final function and Second be a Kotlin class extending First with a function of the same name like the final function in First class, example:
// Java class
class First {
final void foo() { }
}
// Kotlin class
class Second: First() {
fun foo() { }
}
Obviously, it’s wrong because the final function foo() can not be overridden. However, compilation pass successfully and in run-time I get java.lang.LinkageError: Method void Second.foo() overrides final method in class First.
Is this correct behavior of compiler? I supposed that there will be some validations for this case. Thank you!

Specifying method's behaviour via EXPECT_CALL vs in body

From what I understand gmock (and I'm new to it) EXPECT_CALL allows for specifying how a method will behave when it's called (in this case I'm mostly interested in what it will return). But I could just as well define the method explicitly with its body. Example:
class Factory
{
int createSomething();
};
class MockFactory : public Factory
{
MOCK_METHOD0(createSomething, int());
};
int main()
{
...
int something(5);
MockFactory mockFactory;
EXPECT_CALL(mockFactory, createSomething()).WillRepeatedly(Return(something));
...
}
vs
class MockFactory : public Factory
{
int createSomething()
{
return 5;
}
};
Now, if createSomething were to behave differently (return different things) in different scenarios then obviously I should use EXPECT_CALL. But if it's going to always return the same thing wouldn't it be better to just explicitly define the method's body? (Note that other methods in the mocked class might still use EXPECT_CALL.)
When you define a method you miss all the flexibility that mocking that method can give you in the tests.
If you need to assert in a test that createSomething gets called, you can only do it if you have mocked it, not if you have a standard method definition. Not in this case, but in case of methods taking parameters, it's even better to have a mock.
If you need to set up a default action that your method should perform, even when you don't set any expectations on it, do so using ON_CALL macro in the SetUp member function of a TestFixture.