Refactor code to not throw Mockito's UnnecessaryStubbingException - java

I have a simple view with button that starts Intent.ACTION_PICK for result and than displays chosen contact on screen. To do that following steps must be taken:
check if android.permission.READ_CONTACTS is granted
open contact activity
select contact and go back to app
check for android.permission.READ_CONTACTS again
find contact by given uri
show contact on screen
I want to test scenario when one open contacts than revokes permission and goes back to app with selected contact. Expected result is not to call method that find contacts by its uri.
Unfortunately current implementation throws:
org.mockito.exceptions.misusing.UnnecessaryStubbingException:
for:
whenever(interactor.getContact(any())).thenReturn(Maybe.just(Contact()).doOnSuccess { find = true })
I know that I can replace StrictStubs with Silent but I'm looking for better solution with refactoring current code.
All necessary class and test:
class Contact
interface View {
val contactClicks: Observable<Any>
fun setContact(contact: Contact)
}
interface Interactor {
fun getContact(uri: String): Maybe<Contact>
}
interface Router {
fun goToContacts(): Maybe<String>
}
interface Permissioner {
fun requestReadContacts(): Single<Boolean>
}
class Presenter(
private val view: View,
private val interactor: Interactor,
private val router: Router,
private val permissioner: Permissioner
) {
private val disposables: CompositeDisposable = CompositeDisposable()
fun bindView() {
view.contactClicks
.flatMapSingle { permissioner.requestReadContacts() } //ask first time before opening contacts
.filter { it }
.flatMapMaybe { router.goToContacts() }
.flatMapMaybe {
permissioner.requestReadContacts() //ask second time before using ContentResolver
.filter { granted -> granted }
.flatMap { _ -> interactor.getContact(it) }
}
.subscribeBy { view.setContact(it) }
.addTo(disposables)
}
}
#RunWith(MockitoJUnitRunner.StrictStubs::class)
class PresenterTest {
#Mock
lateinit var view: View
#Mock
lateinit var router: Router
#Mock
lateinit var permissioner: Permissioner
#Mock
lateinit var interactor: Interactor
#InjectMocks
lateinit var presenter: Presenter
private val contactClickSubject = PublishSubject.create<Any>()
#Before
fun setUp() {
whenever(view.contactClicks).thenReturn(contactClickSubject)
}
#Test
fun shouldNotFindContactWhenReturnedWithUriAndPermissionNotGrantedSecondTime() {
var firstTimeAsk = true
whenever(permissioner.requestReadContacts()).thenReturn(Single.fromCallable {
if (firstTimeAsk) {
firstTimeAsk = false
return#fromCallable true
} else {
return#fromCallable false
}
})
whenever(router.goToContacts()).thenReturn(Maybe.just("contact"))
var find = false
whenever(interactor.getContact(any())).thenReturn(Maybe.just(Contact()).doOnSuccess { find = true })
presenter.bindView()
contactClickSubject.onNext(Any())
assertFalse(find)
}
}

UnnecessaryStubbingException means you are stubbing something, but not really using it. And that's correct, in your case interactor.getContact should be never called in test - this is desired behaviour. So there is no point in stubbing it.
The simplest solution would be to remove unnecessary variable var find = false and stubbing - substitute them with assertion at the end of your test:
verify(interactor, never()).getContact(any())
This is equivalent to your current solution but more straightforward than using helper variables.

Related

MockK Mocking a Surface object for Android

I'm trying to test some code, and I need a valid Surface object for Android in order to properly test it, since a lot of the code checks if there is a valid surface (ie surface.isValid() where surface is of the Surface class: https://developer.android.com/reference/android/view/Surface)
With MockK, is there a way I can essentially perform this Mock? I have tried the following:
private lateinit var mymonitor : Monitor
#MockK private lateinit var mockContext : Context
#MockK private lateinit var mockSurface : Surface
#Before
fun setup() {
init(this, relaxed = true)
mockkConstructor(Monitor::class)
mockkConstructor(Surface::class)
every { anyConstructed<Monitor>().getApplicationContext() } returns mockContext
every { anyConstructed<Surface>().isValid() } returns true
mymonitor = spyk(Monitor())
mymonitor.init(mockContext, mockSurface)
In the Monitor.java file
protected void init(Context mockContext, Surface mockSurface) {
if (mockSurface.isValid()) {
Log.d(TAG, "Surface is valid...");
// proceeds with init
} else {
Log.d(TAG, "Surface NOT valid...");
}
}
When I do this, I get the Log that Surface NOT valid, so basically the Surface object is not valid I suppose. Am I doing something wrong?
Try remove the anyConstructed:
private lateinit var myMonitor : Monitor
private val mockContext : Context = mockk(relaxed = true)
private val mockSurface : Surface = mockk(relaxed = true)
#Before
fun setup() {
every { mockSurface.isValid() } returns true
myMonitor = spyk(Monitor())
myMonitor.init(mockContext, mockSurface)
}
PD: In case of needing to use a real context, it would be necessary to apply Robolectric or an android test.

How to initiate work flow or start chain of actions in java/kotlin

How to initiate work flow or start chain of actions in java/kotlin?
I have a workflow which has severals steps. Each step is executed based on if conditions, if the condition satisfied we execute the step and if not satisfied move on to next step.
Step1: create an interface
interface Chain {
fun setNextChain(nextChain: Chain?)
fun getChainResponse(someInput: SomeInputClass): ChainResponse?
}
Step2: create classes for ech steps in your workflow and implement the chain interface
class Step1InWorkflow : Chain {
private var nextInChain: Chain? = null
override fun setNextChain(nextChain: Chain?) {
nextInChain = nextChain
}
override fun getChainResponse(
someInput: SomeInputClass
): ChainResponse? {
return if ( execute step1 based on some condition) {
// FLOW -> Step 1
getStepOneResponse(contractant)
} else {
setNextChain(Step2InWorkflow())
nextInChain?.getChainResponse(someInput: SomeInputClass)
}
}
private fun getStepOneResponse(input: Input): ChainResponse {
// logic and return response
}
}
Step3: End of workflow
class Step2InWorkflow : Chain {
private var nextInChain: Chain? = null
override fun setNextChain(nextChain: Chain?) {
nextInChain = nextChain
}
override fun getChainResponse(someInput: SomeInputClass): ChainResponse? {
// some business logic
return getStep2Response(input)
}
private fun getStep2Response(input:Input): ChainResponse {
// return response
}
}

how to resolve - Parameter specified as non-null is null

I have unit test in which I am trying to check is a use case is called with the right parameters but I get an error
java.lang.IllegalArgumentException: Parameter specified as non-null is null: method com.xx.xxx.clean.orderview.domain.OnStandUseCaseCoroutine$Params.<init>, parameter serviceType
#Test
fun `when notifyOnStand is called then we create a TimestampedAction with the correct user id, vehicle, timestamp and pass that to the usecase`() {
val actionCaptor = argumentCaptor<TimestampedAction>()
val timestamp = DateTime.now()
every(noServiceRequiredBus.get()).thenReturn(Observable.just(REQUESTED))
every(timingsUpdater.timestampCalculator(any(), any())).thenReturn(timestamp)
baseOrderViewPresenter.setView(view)
baseOrderViewPresenter.notifyOnStand()
runBlocking {
verify(onStandUseCaseCoroutine).run(OnStandUseCaseCoroutine.Params(any(), any(), capture(actionCaptor)))
}
}
Use case which will get called when when called baseOrderViewPresenter.notifyOnStand() from tets case
class OnStandUseCaseCoroutine #Inject constructor(
private val orderRepository: OrderRepository,
private val serviceOrderTypeProvider: ServiceOrderTypeProvider
) : UseCaseCoroutine<GenericResponse, OnStandUseCaseCoroutine.Params> (){
override suspend fun run(params: Params) =
orderRepository.notifyOnStandSuspend(serviceOrderTypeProvider.apiPathFor(params.serviceType), params.id, params.action)
data class Params(val serviceType: String, val id: String, val action: TimestampedAction)
}
Presenter layer which has the call to use case
private fun onstandUseCaseCoroutines(serviceType: String, id: String, action: TimestampedAction, callback: (GenericResponse?) -> Unit) {
try {
onStandUseCaseCoroutine(OnStandUseCaseCoroutine.Params(serviceType, id, action)) {
callback.invoke(it)
}
} catch (exception: Exception) {
onStandResponseErrors()
}
}
how can I fix this please
I tried changing to bellow code but that did not fix it, I am not sure what to do the capture(actionCaptor) bit if that is the issue
runBlocking {
verify(onStandUseCaseCoroutine).run(OnStandUseCaseCoroutine.Params(anyString(), anyString(), capture(actionCaptor)))
}
Any suggestions please
Thanks
R

Using coroutines in a right way

I am implementing the coroutine for first time. I am following MVP pattern for a simple login app. Here is my code flow -
The login button clicked will follow this direction -
LoginFragment -> LoginPresenter -> Repository -> APIRepository -> RetrofitInterface
The login response will follow this direction -
RetrofitInterface -> APIRepository -> Repository -> LoginPresenter -> LoginFragment
Here is the code -
RetrofitInterface.kt
#POST("login")
fun loginAPI(#Body loginRequest: LoginRequest): Deferred<LoginResponse>?
Here is my Result.kt
sealed class Result<out T : Any> {
class Success<out T : Any>(val data: T) : Result<T>()
class Error(val exception: Throwable, val message: String = exception.localizedMessage) : Result<Nothing>()
}
APIRepository.kt
override suspend fun loginAPICall(loginRequest: LoginRequest) : Result<LoginResponse>? {
try {
val loginResponse = apiInterface?.loginAPI(loginRequest)?.await()
return Result.Success<LoginResponse>(loginResponse!!)
} catch (e : HttpException) {
return Result.Error(e)
} catch (e : Throwable) {
return Result.Error(e)
}
}
Repository.kt
override suspend fun loginUser(loginRequest: LoginRequest): Result<LoginResponse> {
if (isInternetPresent(context)) {
val result = apiRepositoryInterface?.loginAPICall(loginRequest)
if (result is Result.Success<LoginResponse>) {
val loginData = result.data
cache?.storeData(loginData)
}
return result!!
} else {
return Result.Error(Exception())
}
}
How do I launch a coroutine now in my presenter? I need to execute this API call on a background thread and publish the results on UI thread?
You need to launch a coroutine in a Presenter using local scope and injected CoroutineContext to be able to change it, for example in Unit Tests:
class Presenter(
private val repo: Repository,
private val uiContext: CoroutineContext = Dispatchers.Main
) : CoroutineScope { // creating local scope
private var job: Job = Job() // or SupervisorJob() - children of a supervisor job can fail independently of each other
// To use Dispatchers.Main (CoroutineDispatcher - runs and schedules coroutines)
// in Android add dependency: implementation 'org.jetbrains.kotlinx:kotlinx-coroutines-android:1.0.1'
override val coroutineContext: CoroutineContext
get() = uiContext + job
fun detachView() {
// cancel the job when view is detached
job.cancel()
}
fun login(request: LoginRequest) = launch { // launching a coroutine
val result = repo.loginUser(request) // calling 'loginUser' function will not block the Main Thread, it suspends the coroutine
//use result, update UI
when (result) {
is Success<LoginResponse> -> { /* update UI when login success */ }
is Error -> { /* update UI when login error */ }
}
}
}
you can use coroutine in this way
private var parentJob = Job()
private val coroutineContext: CoroutineContext
get() = parentJob + Dispatchers.Main
private val scope = CoroutineScope(coroutineContext)
scope.launch(Dispatchers.IO) {
// your api call
}
you can call parentJob.cancel() to cancel the job or call it in onClear of ViewModel

How to restrict function invocation to a particular thread/executor

I'm currently designing database for a mobile application. Recently I found very useful function to access database in background:
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
Besides that I figured out that don't need synchronization code as the database will be accessed only in one thread (i.e the thread used by SingleThreadExecutor).
The only issue is that the following methods have to be restricted to be invoked only through ioThread function (or using IO_EXECUTOR).
abstract class MyDatabase : RoomDatabase() {
companion object {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
Is it possible to achieve this in Kotlin/Java?
UPDATE: for now I have this implementation but think there should be better ones
// App.kt file
private val IO_EXECUTOR = Executors.newSingleThreadExecutor()
private var IO_THREAD_ID: Long = -1L
private fun getIOThreadId(): Long {
if (IO_THREAD_ID == -1L)
IO_THREAD_ID = IO_EXECUTOR.submit(Callable<Long> { Thread.currentThread().id }).get()
return IO_THREAD_ID
}
fun notInIOThread() = Thread.currentThread().id != getIOThreadId()
fun ioThread(f : () -> Unit) {
IO_EXECUTOR.execute(f)
}
and then use notInIOThread() in init() and getInstance() functions
If you absolutely need to make sure that the code is running on the correct thread, you could make use of a custom thread and then checking Thread.currentThread() for the interface.
private interface MarkedIOThread // Marker interface
private val IO_EXECUTOR = Executors.newSingleThreadExecutor { r ->
return object : Thread(r), MarkedIOThread
}
fun notInIOThread(): Boolean = Thread.currentThread() !is MarkedIOThread
Yes, you can use android annotations`s Worker Thread annotation.
When you annotate a method or class with #WorkerThread, android will give you lint errors if you call it from the UI thread.
You can read more about the #WorkerThread here: https://developer.android.com/reference/android/support/annotation/WorkerThread
And more about android annotations here: https://developer.android.com/studio/write/annotations
I would suggest that you should check room library: https://developer.android.com/topic/libraries/architecture/room
It is very powerful, if you don't have any specific reason to create a database library, room is your best bet.
I assume you want the functions to be called only inside ioThread code block, otherwise there'd be a type error. First make them member functions of a class with user-code-inaccessible constructor so others cannot call it directly:
class MyDslClass internal constructor() {
fun init(context: Context) { ... }
fun getInstance() { ... }
}
And ioThread should be:
fun ioThread(f : MyDslClass.() -> Unit) {
val dsl = MyDslClass()
IO_EXECUTOR.execute { dsl.f() }
}
Then you can restrict calls to those functions only inside ioThread block.
fun main(args: Array<String>) {
ioThread {
getInstance() // Ok
}
// cannot call `getInstance` since I cannot construct a `MyDslClass`
}

Categories