MockK Mocking a Surface object for Android - java

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.

Related

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

Passing variable to class constructor by inject() in java/kotlin

I have my main class set up like this:
class MyView : View() {
val controller: PollController by inject()
etc
}
I want to pass in a variable (like a string for a pathfile)
class PollController : Controller() {
val currentData = SimpleStringProperty()
val stopped = SimpleBooleanProperty(true)
val scheduledService = object : ScheduledService<DataResult>() {
init {
period = Duration.seconds(1.0)
}
override fun createTask() : Task<DataResult> = FetchDataTask()
}
fun start() {
scheduledService.restart()
stopped.value = false
}
inner class FetchDataTask : Task<DataResult>() {
override fun call() : DataResult {
return DataResult(SimpleStringProperty(File(**path**).readText()))
}
override fun succeeded() {
this#PollController.currentData.value = value.data.value // Here is the value of the test file
}
}
}
[DataResult is just a SimpleStringProperty data class]
so that the functions within class PollController can refer to a pathfile. I can't figure out how the injection works; #Inject always stays red and adding constructors throws out the Controller() object return
This is a good use case for Scopes. A Scope isolates Controllers and ViewModels so that you can have different scopes with different versions of your resources. If you also add a ViewModel to hold your context, you can do something like this:
class MyView : View() {
val pc1: PollController by inject(Scope(PollContext("somePath")))
val pc2: PollController by inject(Scope(PollContext("someOtherPath")))
}
Now add the context object to your Controller, so that you can access it from any function within the controller instance.
class PollController : Controller() {
val context : PollContext by inject()
}
The context object could contain both input/output variables. In this example it takes the input path as a parameter. Be aware that such a ViewModel cannot be instantiated by the framework, so you have to put one of these into the Scope manually like I showed above.
class PollContext(path: String) : ViewModel() {
val pathProperty = SimpleStringProperty(path)
var path by pathProperty
val currentDataProperty = SimpleStringProperty()
var currentData by currentDataProperty
}
You could do something like:
Main app
class MyApp: App(MainView::class)
MainView
class MainView : View() {
override val root = hbox {
add(FileView("C:\\passedTestFile.txt"))
}
}
FileView
class FileView(filePath: String = "C:\\test.txt") : View() {
private val controller : FileController by inject(params = mapOf("pathFile" to filePath))
override val root = hbox {
label(controller.pathFile)
}
}
FileController
class FileController: Controller() {
val pathFile : String by param()
}
The controller acceps the path by a parameter using by param(), the view expects this variable by a constructor parameter and using it when injection the controller (The inject delegate has an optional params argument). The only thing left when you are using this view (in MainView) that you pass the file path on instance creation.
Ends up with:
However this works I would create 3 layers rather than two, the classic model-view-controller (or any derivate) layers and I would store the file path in the model.

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`
}

How to pass a context as a parameter

I'm an beginner in kotlin and im trying to pass a context as a parameter, but isnt working...
these are my codes:
FUNCTION saveDatabase
private fun saveDatabase(context : Context){
val fightersName = Match(1, fighter1.toString(), fighter2.toString(),
minute.toInt(), round.toInt())
val db = DBContract(context)
db.insertData(fightersName)
}
CALLING THE FUNCTION
saveDatabase(context)
WARNING
Typemismatch
Required: Context
Found: Context?
This class is a fragment that extends of a Fragment()
your function requires a non null Context object, whereas you are calling it with a nullable and mutable Context object. If you are sure your context is not null, call
saveDatabase(context!!)
!! means that you vouch for the object to be non null
Or you can check your function for safety, then change your function to
private fun saveDatabase(context : Context?){
if(context != null){
val fightersName = Match(1, fighter1.toString(), fighter2.toString(),
minute.toInt(), round.toInt())
val db = DBContract(context)
db.insertData(fightersName)
}
}
The getContext method that you're accessing as the context property in Kotlin has a nullable type Context? - since it will return null when your Fragment isn't attached to an Activity.
One way to deal with the error is to first fetch its value, and perform a null check before you call your function:
val context = context
if (context != null) {
saveDatabase(context)
}
The same check using let, in two different forms:
context?.let { ctx -> saveDatabase(ctx) }
context?.let { saveDatabase(it) }
You can also use requireContext if you are absolutely sure that your Fragment is attached to an Activity - this returns a non-nullable Context, or throws an exception if there isn't one available.
saveDatabase(requireContext())
it so easy. Try as follow
private fun saveDatabase(context : Context?){
val fightersName = Match(1, fighter1.toString(), fighter2.toString(),
minute.toInt(), round.toInt())
val db = DBContract(context)
db.insertData(fightersName)
}
If you are new in Android with kotlin you will surely need an "always available" context. This is the way:
class App : Application() {
companion object {
lateinit var instance: App
}
override fun onCreate() {
super.onCreate()
instance = this
}
}
then you just need to pass:
val db = DBContract(App.instance)
Be sure of modifying the manifest:
<application
android:name=".App"
...>

Refactor code to not throw Mockito's UnnecessaryStubbingException

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.

Categories