How to correctly use Mockito's verify on a spring #Service test - kotlin

I have this service (all in kotlin):
#Service
class MyService {
fun getSomeString(): String = "test"
}
And this integration test class:
#RunWith(SpringRunner::class)
#SpringBootTest
#EmbeddedKafka // used on some kafka tests
class BasicTests {
and method:
#Test
fun `test method count`() {
// here I have a kafka producer sending a message to a topic that ends up
// calling myService.getSomeString via #KafkaListener from other services
verify(someObjectRelatedToMyService, atLeast(1)).getSome()
}
In the place of someObjectRelatedToMyService I tried to use
#Autowired
lateinit var myService: MyService
But then I got Argument passed to verify() is of type MyService and is not a mock!
But when I use
#Mock
lateinit var myMock: MyService
I get Actually, there were zero interactions with this mock.
And actually, to me it makes sense, since my mock wasn't called, but my real service at the application was.
Is it possible to count method calls from my real object?

You can spy on the real object to count method calls on it like this:
#Test
fun `test method count`() {
Mockito.spy(someObjectRelatedToMyService)
verify(someObjectRelatedToMyService, atLeast(1)).getSome()
}
As you can see, the only thing you have to do is to call the spy method which enables tracking interactions with the target object.
When adding this call before the verify method, you should not get the error anymore that the object is not a mock.

[Posting here since no rep to comment] Have you tried using a #Spy? Then you could specify which methods to mock and which methods to call. I supposed you can also apply Mockito.verify on spies...

Related

Hilt Singleton doesn't seems to work in my Service

I'm facing an issue, like if my repository injected was not a Singleton.
I have a repository (in reality many, but let's make it simple) marked as #Singleton
#Module
#InstallIn(SingletonComponent::class)
class AppModule {
#Provides
#Singleton
fun provideSettingsRepository(#ApplicationContext context: Context): SettingsRepository {
return SettingsRepositoryImpl(context)
}
}
Here the implementation of my repository :
class SettingsRepositoryImpl(context: Context) : SettingsRepository {
private var _flow = MutableStateFlow("init value")
override fun getFlow(): StateFlow<String?> = _flow.asStateFlow()
override fun setMyValue(value:String) {
_flow.value = value
}
}
When I use it apart of my service (in some viewModels or others class with DI), it work perfectly. Today I implemented an AIDL service and wanted to do some DI. I had to use field injection because the service constructor has to be empty. It seems like the update made from my application isen't reported on my "TestApplication" who consume the Service (like if I had two instance of my repository).
Here the code of my service :
#AndroidEntryPoint
class AppService : Service() {
#Inject lateinit var settingsRepository: SettingsRepository
fun someActionOnMyRepository() {
settingsRepository.setMyValue("whatever")
}
}
When I set the value from my UI (viewModel or any other class who as the repository injected), it's not updated in my service. The flow doesn't contains the new value (tested by debug or logcat).
I'm expecting my settingsRepository to be a singleton. What am I missing ? Is it because the field injection ?
Best regards
Ok, the problem was not from Hilt but about how i declared my service in my AndroidManisfest.xml
<service android:name=".services.MyAppService"
android:process=":remote" <----- THIS
android:exported="true">
Making it like that make it on another process. That mean it's like another app instance (so no more Singleton / SharedPreferences).

Guice & Dropwizard - Field Injection not working - while Constructor Injection does

I have a test class that looks something like this
Behind the scenes, we're using Guice and DropwizardAwareModule to configure the binding and provide instantiated classes/beans.
class SomeTest {
companion object {
#RegisterExtension
#JvmField
val app = TestGuiceyAppExtension.forApp(MyServer::class.java)
.config(configFileName).hooks(GuiceyConfigurationHook {
builder(it)
}).create()
}
#Inject
#Named("something")
private lateinit var someClass: SomeClass
}
The SomeClass is defined in the following way:
class SomeClass(firstClass: FirstClass, secondClass: SecondClass) {
}
With no constructor injection.
In a separate DropwizardAwareModule, I define a Provides function that provides 2 possible instances of SomeClass. For example -
#Provides
#Named("something")
fun getSomeClass(firstClass: FirstClass, secondClass: SecondClass) {
return SomeClass(firstClass, secondClass)
}
The test class fails to inject SomeClass, claiming it doesn't have a no-args constructor, nor an #Inject annotated constructor, fair enough.
However, if I transform the field injection into a constructor injection, it works flawlessly.
That is - this configuration works well, and the SomeClass instance I provided in the module above, shows up alright.
class SomeTest #Inject constructor(#Named("something") someClass: SomeClass) {
}
Why is it so? is it because of some limitation in test classes? or is it something to do with #Provides generating an immutable instance, whereas field injection requires mutable objects?
Thanks!

How to avoid NPEs from default parameters in mocked classes?

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.

Testcontainers: execute TC_INITSCRIPT at each test

In a quakus project, I successfully set up testcontainers using only the following configuration:
%test.quarkus.datasource.driver=org.testcontainers.jdbc.ContainerDatabaseDriver
%test.quarkus.hibernate-orm.dialect=org.hibernate.dialect.PostgreSQL9Dialect
%test.quarkus.datasource.url=jdbc:tc:postgresql:11:///dbname?TC_INITSCRIPT=file:my-file.sql
This is amazing how easy it is.
However, as I test the deletion of entities, I'd like to execute the initscript before each test, i.a. start each test with the initial DB.
Any idea how to achieve it?
I also tested by creating the PostgreSQLContainer from the test class in order to manage its lifecycle as I need. The problem is that the container port value is random, I need to set it in quarkus configuration but it doesn't work (it seems to be too late: "Connection to 127.0.0.1:6432 refused"). I did it this way:
#Testcontainers
#QuarkusTest
class MyTest {
class MyPostgreSQLContainer(imageName: String) : PostgreSQLContainer<MyPostgreSQLContainer>(imageName)
companion object {
#Container
val postgres = MyPostgreSQLContainer("postgres:11")
.withDatabaseName("integtest")
.withUsername("postgres")
.withPassword("pwd")
.withExposedPorts(5432)
#BeforeAll
#JvmStatic
internal fun beforeAll() {
postgres.start()
System.setProperty("QUARKUS_DATASOURCE_JDBC_URL", "jdbc:postgresql://127.0.0.1:${postgres.firstMappedPort}/kpi_integtest");
println("BeforeAll init() method called")
}
}
with the application.properties config:
quarkus.datasource.jdbc.url=jdbc:postgresql://127.0.0.1:6432/integtest

guice injection: difference among getBinding/getExistingBinding/getProvider and getInstance

I have a PropertiesModule that extends AbstractModule and contains application constants that I use throughout the project:
class PropertiesModule: AbstractModule(), Serializable {
companion object {
const val APP_NAME = "MyAppName"
...
}
override fun configure() {
...
}
}
Then I use the PropertiesModule to create the injector:
...
val injector = Guice.createInjector(
PropertiesModule(),
...
)
And later when I use the injector to get the property value, I have multiple choices. I could do:
val appName = injector.getInstance(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
)
or
val appName = injector.getExistingBinding(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
).provider.get()
or
val appName = injector.getProvider(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
).get()
I read that in general getInstance should be avoided. But I'm not sure what is the difference among them.
If you've just created your Injector, use getInstance. Otherwise, try to get your object from a narrower injection.
getBinding and getExistingBinding are effectively both for reflective purposes:
[Binding is] a mapping from a key (type and optional annotation) to the strategy for getting instances of the type. This interface is part of the introspection API and is intended primarily for use by tools.
Though it would probably work to some degree, I'd recommend against getExistingBinding, if only because it has the counterintuitive behavior of not creating Just-In-Time bindings if they do not already exist, as described in the getExistingBinding docs:
Unlike getBinding(Key), this does not attempt to create just-in-time bindings for keys that aren't bound.
This method is part of the Guice SPI and is intended for use by tools and extensions.
getProvider(Class<T>) will procure a Provider<T> from the graph, which is like a single-key Injector that can only create or retrieve instances of a single key from the Injector. Think of it as creating a lambda that calls getInstance for a specific Key, and nothing more.
getInstance is the most important method on Injector, and I expect all Guice applications to call it at least once. If you've just created your Injector, you'll presumably want to either get an instance from it, or inject the #Inject fields of an object. The former happens with getInstance, and the latter with injectMembers. In my opinion, that's the best way to get the first object out of your graph.
However, and this is where the advice you heard comes in: You should probably not use the Injector after that first getInstance or injectMembers call. This is because the goal in Guice is to make independent components that express their dependencies narrowly so you can replace those dependencies easily. This is the major benefit of dependency injection. Though you have the options of stashing the Injector somewhere static, or injecting the Injector itself into your dependencies, that prevents you from knowing exactly what your class's dependencies are: with an Injector injection, you can inject anything in the world.
To demonstrate (please forgive my Kotlin inexperience):
class BadIdea #Inject constructor(injector: Injector) {
fun doSomething() {
// Bad idea: you don't express this dependency anywhere, and this code
// is nearly unusable without a real Guice Injector
val appName = injector.getInstance(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
)
}
}
class WorseIdea {
fun doSomething() {
// Worse idea: same as the above, but now you rely on a static!
val appName = StaticInjectorHolder.getInjector().getInstance(
Key.get(String::class.java, Names.named(PropertiesModule.APP_NAME))
)
}
}
class GoodIdea #Inject constructor(#Named(PropertiesModule.APP_NAME) appName: String) {
fun doSomething() {
// Good idea: you express your dep, and anyone can call the constructor
// manually, including you in your unit tests.
}
}