Using different classes for testing and normal runs in android - android

I'm trying to build an library that helps my application communicate with other devices using bluetooth
In order to achieve this I created an interface like so:
interface IBluetoothAdapter {
....
}
On normal runs I use it like so:
internal class BTAdapter : IBluetoothAdapter {
private val mAdapter = BluetoothAdapter.getDefaultAdapter()
}
and I use it to send messages to the actual bluetooth adapter
when I run my tests I mock IBluetoothAdapter and this works decently
in order to facilitate the above my actual class has this implementation:
class Communicator(val address:String) {
private var mAdapter: IBluetoothAdapter = BTAdapter()
#VisibleForTesting
#TestOnly
fun setAdapter(adapter: IBluetoothAdapter) {
mAdapter = adapter
}
.....
}
Is there a better way to do this?
Basically what I want to do is when the application runs in tests to always use one specific class (the mock) and when it runs normally to always use another (the one I created)

What your code is doing is called Dependency_injection
Is there a better way to do this?
There is not one "better" way to do it but there are different ways to do it that depend on the tools you are using (see why-do-i-need-an-ioc-container-as-opposed-to-straightforward-di-code for details.)
I would have implemented it the same way you have done it because your code can be used without any di containers so it is has less external dependencies.

Related

Passing custom object between activities

I'm following this tutorial on how to use MQTT with Android Studio. In it, they created an MQTTClient class that uses the MQTTAndroidClient library. I want to pass the MQTTClient class from one activity to another. Any suggestions how I might do this? I'm new to Android dev and I'm trying to negotiate serializable/parcelable tools without much know-how. Thanks!
P.S. I'm developing in Kotlin
Passing complex classes between activities is generally a bad idea. For that kind of usage you should use a Singleton and store it in your Application class or something like this.
I don't recommend you to pass the entire MQTTClient through Activities.
I'd suggest you to read this Dependency-Injection manual is more or less what you need, normally you'd use a dependency injection library/framework to do what you want but since is complex to set-up most of them I'd follow the link I've linked before.
Sample code :
// Container of objects shared across the whole app
class AppContainer {
val mqttClient = MQTTClient() //<-- Initialisation
}
Then create a custom Application
class MyApplication : Application() {
// Instance of AppContainer that will be used by all the Activities of the app
val appContainer = AppContainer()
}
Do not forget to add it to manifest.xml with the name attribute.
And then from your Activity you need this MQTTClient you use :
val appContainer = (application as MyApplication).appContainer
val mqttClient = appContainer.mqttClient
What #Ben-J suggested is also a good point, to create a Singleton in kotlin you can use the object keyboard.

Where to do Arrow.io IO.runUnsafeSync() ? ViewModel or Activity/Fragment?

I'm trying to learn the Arrow library and improve my functional programming by transitioning some of my Android Kotlin code from more imperative style to functional style. I've been doing a type of MVI programming in the application to make testing simpler.
"Traditional" Method
ViewModel
My view model has a LiveData of the view's state plus a public method to pass user interactions from the view to the viewmodel so the view model can update state in whatever way is appropriate.
class MyViewModel: ViewModel() {
val state = MutableLiveData(MyViewState()) // MyViewState is a data class with relevant data
fun instruct(intent: MyIntent) { // MyIntent is a sealed class of data classes representing user interactions
return when(intent) {
is FirstIntent -> return viewModelScope.launch(Dispatchers.IO) {
val result = myRoomRepository.suspendFunctionManipulatingDatabase(intent.myVal)
updateStateWithResult(result)
}.run { Unit }
is SecondIntent -> return updateStateWithResult(intent.myVal)
}
}
}
Activity
The Activity subscribes to the LiveData and, on changes to state, it runs a render function using the state. The activity also passes user interactions to the view model as intents (not to be confused with Android's Intent class).
class MyActivity: AppCompatActivity() {
private val viewModel = MyViewModel()
override fun onCreateView() {
viewModel.state.observe(this, Observer { render(it) })
myWidget.onClickObserver = {
viewModel.instruct(someIntent)
}
}
private fun render(state: MyViewState) { /* update view with state */ }
}
Arrow.IO Functional Programming
I'm having trouble finding examples that aren't way over my head using Arrow's IO monad to make impure functions with side effects obvious and unit-testable.
View Model
So far I have turned my view model into:
class MyViewModel: ViewModel() {
// ...
fun instruct(intent: MyIntent): IO<Unit> {
return when(intent) {
is FirstIntent -> IO.fx {
val (result) = effect { myRoomRepository.suspendFunctionManipulatingDatabase(intent.myVal) }
updateStateWithResult(result)
}
is SecondIntent -> IO { updateStateWithResult(intent.myVal) }
}
}
}
I do not know how I am supposed to make this IO stuff run in Dispatcher.IO like I've been doing with viewModelScope.launch. I can't find an example for how to do this with Arrow. The ones that make API calls all seem to be something other than Android apps, so there is no guidance about Android UI vs IO threads.
View model unit test
Now, because one benefit I'm seeing to this is that when I write my view model's unit tests, I can have a test. If I mock the repository in order to check whether suspendFunctionManipulatingDatabase is called with the expected parameter.
#Test
fun myTest() {
val result: IO<Unit> = viewModel.instruct(someIntent)
result.unsafeRunSync()
// verify suspendFunctionManipulatingDatabase argument was as expected
}
Activity
I do not know how to incorporate the above into my Activity.
class MyActivity: AppCompatActivity() {
private val viewModel = MyViewModel()
override fun onCreateView() {
viewModel.state.observe(this, Observer { render(it) })
myWidget.onClickObserver = {
viewModel.instruct(someIntent).unsafeRunSync() // Is this how I should do it?
}
}
// ...
}
My understanding is anything in an IO block does not run right away (i.e., it's lazy). You have to call attempt() or unsafeRunSync() to get the contents to be evaluated.
Calling viewModel.instruct from Activity means I need to create some scope and invoke in Dispatchers.IO right? Is this Bad(TM)? I was able to confine coroutines completely to the view model using the "traditional" method.
Where do I incorporate Dispatchers.IO to replicate what I did with viewModelScope.launch(Dispatchers.IO)?
Is this the way you're supposed to structure a unit test when using Arrow's IO?
That's a really good post to read indeed. I'd also recommend digging into this sample app I wrote that is using ArrowFx also.
https://github.com/JorgeCastilloPrz/ArrowAndroidSamples
Note how we build the complete program using fx and returning Kind at all levels in our architecture. That makes the code polymorphic to the type F, so you can run it using different runtime data types for F at will, depending on the environment. In this case we end up running it using IO at the edges. That's the activity in this case, but could also be the application class or a fragment. Think about this as what'd be the entry points to your apps. If we were talking about jvm programs the equivalent would be main(). This is just an example of how to write polymorphic programs, but you could use IO.fx instead and return IO everywhere, if you want to stay simpler.
Note how we use continueOn() in the data source inside the fx block to leave and come back to the main thread. Coroutine context changes are explicit in ArrowFx, so the computation jumps to the passed thread right after the continueOn until you deliberately switch again to a different one. That intentionally makes thread changes explicit.
You could inject those dispatchers to use different ones in tests. Hopefully I can provide examples of this soon in the repo, but you can probably imagine how this would look.
For the syntax on how to write tests note that your program will return Kind (if you go polymorphic) or IO, so you would unsafeRunSync it from tests (vs unsafeRunAsync or unsafeRunAsyncCancellable in production code since Android needs it to be asynchronous). That is because we want our test to be synchronous and also blocking (for the latter we need to inject the proper dispatchers).
Current caveats: The solution proposed in the repo still doesn't care of cancellation, lifecycle or surviving config changes. That's something I'd like to address soon. Using ViewModels with a hybrid style might have a chance. This is Android so I'd not fear hybrid styles if that brings better productivity. Another alternative I've got in mind would maybe be something a bit more functional. ViewModels end up retaining themselves using the retain config state existing APIs under the hood by using the ViewModelStore. That ultimately sounds like a simple cache that is definitely a side effect and could be implemented wrapped into IO. I want to give a thought to this.
I would definitely also recommend reading the complete ArrowFx docs for better understanding: https://arrow-kt.io/docs/fx/ I think it would be helpful.
For more thoughts on approaches using Functional Programming and Arrow to Android you can take a look to my blog https://jorgecastillo.dev/ my plan is to write deep content around this starting 2020, since there's a lot of people interested.
In the other hand, you can find me or any other Arrow team maintainers in the Kotlinlang JetBrains Slack, where we could have more detailed conversations or try to resolve any doubts you can have https://kotlinlang.slack.com/
As a final clarification: Functional Programming is just a paradigm that resolves generic concerns like asynchrony, threading, concurrency, dependency injection, error handling, etc. Those problems can be found on any program, regardless of the platform. Even within an Android app. That is why FP is an option as valid for mobile as any other one, but we are still into explorations to provide the best APIs to fulfill the usual Android needs in a more ergonomic way. We are in the process of exploration in this sense, and 2020 is going to be a very promising year.
Hopefully this helped! Your thoughts seem to be well aligned with how things should work in this approach overall.

Populate list with instantiated classes dynamically with Kotlin on Android

I have an abstract class and all classes in some package derive from it. Is there a way to create a list that dynamically instantiates all these classes that reside in some package when using Kotlin on Android?
Here is an example:
com.example.service
BaseService
com.example.service.emailservice
GmailService
OutlookService
All classes in com.example.service.emailservice derive from BaseService abstract class that resides in com.example.service. I want to create a list that contains GmailService and OutlookService objects. I could instantiate them manually and add them to a list, but in future I may add new service, lets say YandexService, which should appear in list too. This requires manual instantiation again. Is there a way to automatically instantiate classes that reside in some package?
There are two mayor ways to do it.
The first one - easier and dirtier one called Reflection.
You may find a lot of examples in java. Not so much in Kotlin though, but from what I have read here it is more than possible.
Usage of Reflection though, is not recommended in production, and generally considered as a bad approach to fulfill something.
The second way is Annotation Processors - this way is way harder. It is considered a clean way to do such tasks though and it is a general standard for code generating techniques. This way you can do all kinds of magic if you put your mind to it. Here is nice article about how to do it.
Generally I would recommend to use semiautomatic approach.
For example:
In your base service with init method
abstract class BaseService {
abstract fun init(): BaseService
}
Make all your services implement this BaseService
class Service : BaseService() {
override fun init(): BaseService {
return Service()
}
}
...
And then just create a list of classes
val services = listOf(Service(), Service1(), Service2())
and to init them do
services.forEach { it.init() }
This is not very different from what you have and may require some logical and architectural changes in your Services and App overall, but it won't be dirty and it won't require tremendous learning curve and time expenses.
Hope it helps.
use this library
add to gradle.build
implementation 'org.reflections:reflections:0.9.11'
then in your package com.example.service create a class from where you will be creating your Services, let's call it ServiceFactory here is implementation:
package com.example.service
import org.reflections.Reflections
class ServiceFactory {
init {
val reflections = Reflections(javaClass.`package`.name)
val subTypes = reflections.getSubTypesOf(BaseService::class.java)
val yourServices = subTypes.map { it.getConstructor().newInstance() }
yourServices.forEach { println(it.javaClass.name) }
}
}
fun main() {
ServiceFactory()
}
out:
com.example.service.emailservice.OutlookService
com.example.service.emailservice.GmailService
Something you were looking for ?
EDIT: of course you can instantiate this services from different place, but in that case you need to hardcode Reflections("com.example.service")

How to hide an interface in another interface?

I want to write an Android library, which in turn uses another Androd library.
Let's say I want to write libHigh which uses another libLow
There is an interface in libLow:
interface LowLevelInterface{
fun methodA()
}
and I implement this in my higher level library libHigh:
open class OpenClassImpl : LowLevelInterface {
override fun methodA(){//..}
}
It is an 'open' class, because later in app layer I expect to extend from OpenClassImpl.
But I dont want to make the interface 'LowLevelInterface' visible for later upper app level usage.
How can I hide the interface from libLow for the upper app level?
It depends on your existing code whether this will work, or how much effort it will be, but you could have a property implementing the interface instead of doing it directly:
open class OpenClassImpl {
// or protected/private
internal val lowLevelImpl: LowLevelInterface = {
// can access privates of OpenClassImpl here
}
}
and change the relevant calls to pass it.

Android unit testing with Junit: testing network/bluetooth resources

I am slowly becoming obsessed with unit testing. I am trying to develop as much software as I can using test-driven development. I am using JUnit to unit test my android applications.
I have been working on an app that uses bluetooth and am having a hard time unit testing it. I have an Activity that uses BluetoothAdapter to obtain a list of paired and discovered devices. Although it works, I would like to know how to unit test it.
To get the list of paired devices, I call getBondedDevices() on the instance of BluetoothAdapter. The problem is I don't know how to stub or mock this method (or any other bluetoothAdapter method that my Activity calls) so I can't test my Activity against different lists of paired devices.
I thought about using Mockito or trying to subclass BluetoothAdapter to somehow stub out the methods I'm interested in, but it's a final class so I can't do either.
Any ideas on how I could test programs that use BluetoothAdapter or other resources that are (as far as I know) difficult or impossible to stub or mock? As another example, how would you test a program that uses sockets?
thanks in advance for any help
aleph_null
To test your activity, you may refactor your code. Introduce a BluetoothDeviceProvider with a default implementation.
public interface BluetoothDeviceProvider {
Set<BluetoothDevice> getBluetoothDevices();
}
public class DefaultBluetoothDeviceProvider implements BluetoothDeviceProvider {
public Set<BluetoothDevice> getBluetoothDevices() {
return new BluetoothAdapter.getDefaultAdapter().getBondedDevices();
}
}
then inject this new interface, in the activity :
public class MyActivity extends Activity {
private BluetoothDeviceProvider bluetoothDeviceProvider;
public MyActivity(BluetoothDeviceProvider bluetoothDeviceProvider) {
this.bluetoothDeviceProvider = bluetoothDeviceProvider;
}
protected void onStart() {
Set<BluetoothDevice> devices = bluetoothDeviceProvider.getBluetoothDevices();
...
}
...
}
Now the activity seems unit-testable. But the BluetoothDevice is still final and you can't inject a mock in your activity. So you have to refactor this new code and introduce a new interface that wraps the BluetoothDevice... -> an abstraction layer upon the core android classes.
At the end the activity behavior can be checked via various unit tests... So the implementations of the newly introduced interfaces remains to test. To do this, you can :
keep them not (unit) tested, not a big problem for me since they just do delegation
look at PowerMock.
Also check this wiki page about mocking final classes using PowerMock.

Categories

Resources