How to shadow a Kotlin companion object on Robolectric 4.3.1? - android

I want to shadow a Kotlin companion object. The companion object what i want to shadowing is:
class MyLogClass {
companion object {
#JvmStatic
fun logV(tag: String, messageProvider: () -> String) {
if (SPUtils.getLogLevel() >= mLogLevel) {
Log.v(tag, messageProvider.invoke())
}
}
}
}
What I have tried:
// Shadow class...
#Implements(MyLogClass.Companion::class)
class ShadowMyLogClass {
#Implementation
fun v(tag: String, messageProvider: () -> String) {
redirectConsole(tag, messageProvider)
}
private fun redirectConsole(tag: String, messageProvider: () -> String) {
println("[$tag]${messageProvider.invoke()}")
}
}
// And in Testing class...
class TestMyLogClass {
#Test
fun test() {
MyLogClass.logV("some tag") {
"some message"
}
}
}
But what I have tried occur an Error:
Caused by: java.lang.IllegalAccessError: tried to access class kotlin.jvm.internal.DefaultConstructorMarker from class com.example.zspirytus.log.impl.MyLogClass$Companion
It seems that there is lost an constructor method which type is DefaultConstructorMarker, How can I make an DefaultConstructorMarker or other way to create a Shadow MyLogClass? Thanks for your reading and answers!

Here's what I did to shadow a method in the companion object
#Implements(Object::class)
class ShadowObject {
companion object {
#Implementation
#JvmStatic
fun verify(): Boolean {
return true
}
}
}
Use:
#RunWith(AndroidJUnit4::class)
#Config(shadows = [
ShadowObject::class
])
class UserTest {
// Rest of testing class
}
In your case, I'd say you just need to wrap your #Implementation method with companion object, and change #Implements(MyLogClass.Companion::class) to just #Implements(MyLogClass::class)

Related

If i am Calling Robolectric Shadow from kotlin test class it is not getting called but if I call using Java Test class it is called

I Created Shadow in Kotlin and My Real Code is also in Kotlin. I created companion object for which i created shadow --->
Shadow Class --->
#Implements(Test::class)
class TestShadow {
companion object {
#Implementation
#Synchronized
#JvmStatic
fun test(variable: String?): Int {
val value = 9
return 5
}
}
And My Main Class --->
class Test {
companion object {
#Synchronized
#JvmStatic
fun test(variable: String?): Int {
return 8
}
}
and I m calling this as Test.test in my test Kotlin File. Everytime real method is called

How to convert a object expression to lambda in Kotlin? [duplicate]

This question already has answers here:
Passing lambda instead of interface
(5 answers)
Closed 1 year ago.
I am new to Android development. Recently I am learning Kotlin and I am trying to figure out setOnClickListener. However, I encountered a problem in the process of converting object expression to lambda using Kotlin.
step 1. setOnClickListener in Java:
buttonLogin.setOnClickListener(new View.OnClickListener() {
#Override
public void onClick(View view) {
// my code
}
});
step 2. then I convert Java code to Kotlin code using object expression:
buttonLogin.setOnClickListener(object : View.OnClickListener {
override fun onClick(p0: View?) {
// my code
}
})
step 3. then IntelliJ prompts me to convert object expression to lambda:
buttonLogin.setOnClickListener {
// my code
}
It looks more concise, however, I can't understand the logic behind step 3.
So I checked some information online, it says
Any function that receives an interface with a single function can be
substituted by a lambda
It does on setOnClickListener.
But I still can't fully understand, so I defined an interface and class to verify it.
Here is my code:
interface MyInterface {
fun method1()
}
class MyClass {
fun method2(myInterface: MyInterface) {
myInterface.method1()
}
}
fun main() {
val myClass = MyClass()
myClass.method2(object : MyInterface {
override fun method1() {
println("Hello, world.")
}
})
// So how to write the lambda to replace object expression?
}
The code in step 3 is called trailing lambdas
According to Kotlin convention, if the last parameter of a function is a function, then a lambda expression passed as the corresponding argument can be placed outside the parentheses,
If the lambda is the only argument in that call, the parentheses can be omitted entirely:
For example:
fun function(f : (String) -> Unit) {
}
fun main() {
function {
}
}
Check the Kotlin Documentation for this feature
https://kotlinlang.org/docs/lambdas.html#passing-trailing-lambdas
You can convert your code to use this feature
class MyClass {
fun method2(function: () -> Unit) {
function()
}
}
fun main() {
val myClass = MyClass()
myClass.method2 {
println("Hello, world.")
}
// Or you can store the lambda in variable and use it like tihs
val myClass2 = MyClass()
val function = {
println("Hello, world.")
}
myClass2.method2(function)
}
Or just add convert your interface to a functional interface
fun interface MyInterface {
fun method1()
}
class MyClass {
fun method2(myInterface: MyInterface) {
myInterface.method1()
}
}
fun main() {
val myClass = MyClass()
myClass.method2 {
println("Hello, world.")
}
}

Listener declared in a Kotlin Object class

I have an object class in Kotlin which is a manager - let's call it KManager - that manager is inside an independent module (moduleA). There is another module (moduleB) where I'm using KManager.
Rule: moduleB knows about moduleA, but moduleA shouldn't know anything about moduleB.
I created like a bridge (interface) to communicate moduleA with moduleB, because of there is some shared logic that needs to run in both sides. The interface is declared in the KManager as:
//moduleA
object KManager {
var bridgeShared: BridgeShared? = null
....
}
Interface:
interface BridgeShared {
fun foo()
}
Now, I have a class in the moduleB where implements BridgeShared. When the app starts I'm initializing bridgeShared like this:
//moduleB
class BridgeSharedImpl : BridgeShared {
KManager.bridgeShared = this
....
}
I'm getting KManager.bridgeShared in the moduleB and executing the interface's functions in another classes, something like:
KManager.bridgeShared.foo()
The question here is, is it harmful to have a listener declared inside an object Kotlin class and grab it whenever I need it?
NOTE: No real names used here, just to describe the scenario.
UPDATE:
Extra Steps:
moduleA receives like an external event, it is processed and then the result is received by the "Observer" who subscribed to the BridgeShared listener, that "Observer" is the moduleB but moduleA doesn't care about it (the rule).
moduleB
class BridgeSharedImpl : BridgeShared {
KManager.bridgeShared = this
override fun eventProcessed() {
//stuff
}
override fun fetchData() {
//stuff
}
fun callAnotherFunction1() {
KManager.anotherFunction1()
}
}
moduleA
interface BridgeShared {
fun eventProcessed()
fun fetchedData()
}
object KManager {
var bridgeShared: BridgeShared? = null
fun anotherFunction1() {
//not-related to BridgeShared, called from outside
}
fun anotherFunction2() {
//not-related to BridgeShared, called from outside
}
}
class EventProcessor {
fun eventReceived() {
//stuff
KManager.bridgeShared?.eventProcessed()
}
}
class DataFetcher {
fun dataReceived() {
//stuff
KManager.bridgeShared?.fetchedData()
}
}
On the other hand, I'm taking advantage of KManager.bridgeShared in the moduleB to call the same functions inside the same moduleB because I don't have access to the instance of BridgeSharedImpleverywhere, just where it was instantiated.
Now, the moduleB uses the KManager singleton to execute other functions not related to the BridgeShared.
Based on the recommendations, I applied the Factory solution to avoid saving the BridgeShared inside a Singleton.
moduleA
class BridgeFactory(private val bridgeShared: BridgeShared) {
companion object {
lateinit var bridgeFactory: BridgeFactory
fun initialize(bridgeShared: BridgeShared) {
bridgeFactory = BridgeFactory(emmaShared)
}
}
fun eventProcessor(): EventProcessor {
return EventProcessor(bridgeShared)
}
fun dataFetcher(): DataFetcher {
return DataFetcher(bridgeShared)
}
}
class EventProcessor(private val bridgeShared: BridgeShared) {
fun eventReceived() {
//stuff
bridgeShared.eventProcessed()
}
}
class DataFetcher(private val bridgeShared: BridgeShared) {
fun dataReceived() {
//stuff
bridgeShared.fetchedData()
}
}
moduleB
class BridgeSharedImpl : BridgeShared {
init {
BridgeFactory.initialize(this)
}
override fun eventProcessed() {
//stuff
}
override fun fetchData() {
//stuff
}
}

Mocking another parameter on function not working when one of them is a callback interface

I successfully did some tests of asynchronous function with only one callback interface as parameter with mockito-kotlin library but when I try to do a test of same function with another parameter like a String or Integer I receive error:
org.mockito.exceptions.misusing.InvalidUseOfMatchersException:
Invalid use of argument matchers!
2 matchers expected, 1 recorded:
-> at com.example.presentation.presenter.MyCollectionPresenterTest.getComicListByHeroOK(MyCollectionPresenterTest.kt:97)
This exception may occur if matchers are combined with raw values:
//incorrect:
someMethod(anyObject(), "raw String");
When using matchers, all arguments have to be provided by matchers.
For example:
//correct:
someMethod(anyObject(), eq("String by matcher"));
For more info see javadoc for Matchers class.
I´m sure I´m mocking properly callback interface with any() but I don´t know if I´m mocking integer parameter correctly. I tried with any(), anyInt(), eq(1) and any() as Int but always the same error.
Here is the class that I want to test:
#PerFragment
class MyCollectionPresenter #Inject constructor(private val useCase: GetComicListByHeroUseCase) {
#Inject
lateinit var view: MyCollectionView
lateinit var models: List<ComicModel>
fun getComicListByHero(heroId: Int) {
useCase.execute(heroId, object : HeroUseCase.GetComicListByHeroCallback {
override fun onComicListReceived(comicList: List<Comic>) {
models = ComicModelMapper.toModel(comicList)
view.setItems(models)
}
override fun onError() {
view.showMessage()
}
})
}
}
And this is the test class:
class MyCollectionPresenterTest : UnitTest() {
private lateinit var presenter: MyCollectionPresenter
#Mock
private lateinit var useCase: GetComicListByHeroUseCase
#Mock
private lateinit var view: MyCollectionView
#Before
fun setUp() {
presenter = MyCollectionPresenter(useCase)
initializeView()
}
#Test
fun getComicListByHeroOK() {
setupGetComicsCallbackOK()
presenter.getComicListByHero(any())
verify(presenter.view).setItems(emptyList())
}
#Test
fun getComicListByHeroError() {
setupGetComicsCallbackError()
presenter.getComicListByHero(any())
verify(presenter.view).showMessage()
}
private fun initializeView() {
presenter.view = view
}
private fun setupGetComicsCallbackError() {
doAnswer {
val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
callback.onError()
null
}.`when`(useCase).execute(any(), any())
}
private fun setupGetComicsCallbackOK() {
doAnswer {
val callback = it.arguments[0] as HeroUseCase.GetComicListByHeroCallback
callback.onComicListReceived(emptyList())
null
}.`when`(useCase).execute(any(), any())
}
}
This is base unit test class:
#RunWith(MockitoJUnitRunner::class)
abstract class UnitTest {
#Suppress("LeakingThis")
#Rule
#JvmField
val injectMocks = InjectMocksRule.create(this#UnitTest)
}
And this is a class for inject mocks rule:
class InjectMocksRule {
companion object {
fun create(testClass: Any) = TestRule { statement, _ ->
MockitoAnnotations.initMocks(testClass)
statement
}
}
}
Thank you very much for your help and excuse my english.
Regards!
UPDATE: I found the solution and posted as answer.
Finally, I know what I was doing wrong. First at all, it.argument[1] because callback is the second parameter of the function that I want to mock the answer.
And the other thing is that I was mocking the parameter of the function that I want to test presenter.getComicListByHero(1).
Here is the revised code:
#Test
fun getComicListByHeroError() {
setupGetComicsCallbackError()
presenter.getComicListByHero(1)
verify(presenter.view).showMessage()
}
private fun setupGetComicsCallbackError() {
doAnswer {
val callback = it.arguments[1] as HeroUseCase.GetComicListByHeroCallback
callback.onError()
null
}.`when`(useCase).execute(ArgumentMatchers.anyInt(), any())
}
Thank you very much to #voghDev for his help

Kotlin generics inheritance - Type mismatch

I am trying to build a set of providers for realm objects.
Here is an example structure I've tried to build:
Interface:
interface IDataProvider<out T : RealmObject> {
fun getRealmObject(): T
}
Base provider class with companion function for typed provider instantiation:
open abstract class BaseProvider<out T : RealmObject> constructor(protected val context: Context?) : IDataProvider<T> {
companion object {
fun <T : RealmObject, E : BaseProvider<T>> create(context: Context?): E {
if (something) {
return SomeChildProviderProvider(context)
} else {
throw TypeNotSupportedException()
}
}
}
}
And here is a child class:
class SomeChildProvider(context: Context?) : BaseProvider<ChildRealmModel>(context){
override fun getRealmObject(): ChildRealmModel {
throw UnsupportedOperationException("not implemented")
}
}
Problem I have is on the line
return SomeChildProviderProvider(context)
Type mismatch.
Required: E.
Found: SomeChildProvider.
I can't figure out why it does not see that E is actually SomeChildProvider.
Thank you.
P.S. I know that I can cast it to E, but in my opinion, it should not be needed in this situation. Maybe I am missing something obvious here or probably lack of Kotlin knowledge.
UPDATE1:
After the first answer, we have realized that code above does not make much sense since we have to define a type of returning provider and to pass it into create method. Initial idea was that create method returns some type which is BaseProvider subtype. Here are the changes I have made in order to support the initial idea:
IDataProvider
interface IDataProvider {
fun execute(realm: Realm)
fun createModel(realm: Realm): RealmObject
}
BaseProvider
open abstract class BaseProvider constructor(protected val context: Context?) : IDataProvider {
override fun execute(realm: Realm) {
realm.executeTransaction { r ->
createModel(r)
}
}
companion object {
fun create(context: Context?): IDataProvider {
if (something) {
return ChildProvider(context)
} else {
throw TypeNotSupportedException()
}
}
}
}
ChildProvider
class ChildProvider(context: Context?) : BaseProvider(context) {
override fun createModel(realm: Realm): ChildRealmModel {
var realmObject = realm.createObject(ChildRealmModel ::class.java)
//object property initialization
return realmObject
}
}
UI call
BaseProvider.create(context).execute(realm)
Although, createModel method returns RealmObject, it's instance will be of ChildRealmModel. What I don't like about it is that we have to inspect instance type and cast into if we need exact model somewhere else.
Your code is not consistent.
In the function declaration you pledge to return E, which is a subtype of BaseProvider<T> and can be chosen by the user on the call site.
But in the implementation you return SomeChildProviderProvider, which is of course a subtype of BaseProvider<T>, but still can be totally unrelated to E which was chosen by the user.
An example:
class AnotherChildProvider : BaseProvider<ChildRealmModel>(context) {...}
val x = BaseProvider.create<ChildRealmModel, AnotherChildProvider>(context)
What is the type of x? According to the function signature, it must be AnotherChildProvider. But inside the function you return SomeChildProviderProvider, which CAN NOT be casted to AnotherChildProviderProvider.

Categories

Resources