Office Hours — Today, July 28

Saturday, July 25

Jul 28
8:20 AM
Mark M.
has entered the room
8:25 AM
Mark M.
turned on guest access
8:30 AM
Marek D.
has entered the room
Mark M.
hello, Mark!
er, Marek!
how can I help you today?
Marek D.
Hi Mark!
my questions are not that well prepared so I will improvise
Mark M.
my answers are even less prepared! :-)
Marek D.
well sometimes key to the answer is well stated question :)
or correct search phrase in google
ok we decided to use flows
kotlin flows
so i.e. ViewModel has some repository
that exposes a flow
for example I want to have a flow of booleans that location services are enabled
8:35 AM
Marek D.
and ask user to turn them on if not
I uses callbackFlow
where I register broadcast receiver to know if the user turn them off
now I am thinking how can I test this in unit test
let's say I start with location enabled and user disables it
so in real app I would get true, then broadcast receiver then false in collector
in test I imagine
I need to collect 1st one
manually trigger broadcast receiver
and collect 2nd event
there is flow.first()
but not the second()
also subsequent call to first() is not exactly what is needed
Mark M.
let's back up a step: are you looking to unit test the repository or the viewmodel here?
Marek D.
I think repository
Mark M.
OK
Marek D.
so I want to make sure that turning location off emits next event
Mark M.
so, there are two problems: how do you set up the appropriate mocks/fakes to get the repository to do what you want in the test, and how do you assert the results coming out of the Flow
8:40 AM
Mark M.
right now, I don't think there is a TestObserver equivalent for Flow
my main work right now is still using RxJava, not coroutines, so I have not written many Flow tests
IIRC, what I did was collect() the Flow into a MutableList, then assert the contents of the MutableList at various points in the test
in this case, it is an instrumented test, not a unit test, but the same principle holds
I do not know if this is "state of the art" for testing Flow, though my guess is that it is not
but, it worked! :-)
my guess/hope is that, at some point, there will be a dedicated test class for testing the output of a Flow
Marek D.
cancelling the collector jobs feels inconvenien
8:45 AM
Mark M.
yes, hopefully there is a better approach that I just have not encountered yet
if you fail to cancel it, though, you get an error
Marek D.
from runBlockingTest
Mark M.
yes
Marek D.
allright will take a look
another question
if you need location
there is a permission thing
to check you neeed to context
you need context
8:50 AM
Marek D.
to request you need activity/fragment
so let's say I click on some button that says enable permission in my UI
Kumar V.
has entered the room
Kumar V.
Hello everyone
Marek D.
so you usually forward this to VM
Mark M.
(hello, Kumar! I will be with you shortly!)
Marek D.
now you need activity to reuqest permission
Kumar V.
Sure Mark. No issues
Marek D.
and contex to see if you already requested them
sorry activity probably (permission rationale)
so should I pass activity to VM to do this
or should I create some events in VM and listen to them in View
Mark M.
IMHO, no
events or states, emitted by the VM, is a better choice
Marek D.
so I emit event, please request a permission ?
and activity does this
Mark M.
well, that starts to get into the details of your approach between your VM and your activity/fragment, and there are a lot of possibilities
but yes, emitting a event to cause the activity to show the permission dialog is one likely option
8:55 AM
Marek D.
recently I created an interface with bunch of methods in activity
so I don't pass activity but that interface
and all if(s) are in the VM
Mark M.
that is at least better than passing the activity itself, insofar as it is easier for you to write tests
Marek D.
and is easy to mock this interface
Mark M.
right
personally, having the VM make direct calls on an activity/fragment, even via an interface, makes me nervous
mostly, it's a memory leak issue
Marek D.
if all calls are synchronous ?
Mark M.
it would be easy for somebody to accidentally hold onto that interface implementation somewhere that would survive the configuration change
today, right now, you might be thinking of that and avoid making that mistake
my concern is more of tomorrow, and the next day, and the day after that
Marek D.
so how to prevent it ?
Mark M.
don't pass an activity/fragment to a VM, even via an interface
do something else, where the VM is emitting states and/or events
Marek D.
but then I rely on my view
to pass me the information
Mark M.
yes, just as you rely on the view to pass UI events ("the user clicked this button", etc.)
I am not saying that your interface approach will not work -- I just would not be super happy with that technique
Marek D.
well I feel more comfortable If I can test longer flow(s)
9:00 AM
Marek D.
because in that event scenarios
the functionality is achieved because a chain of events happen
Mark M.
let me take a question from Kumar, and I will return to you shortly
Kumar: hi! how can I help you today?
Marek D.
go ahead
Kumar V.
View paste
Hi Mark. This is my first office hours. 
I have requirement of running a task everyday, I tried workmanager but it is not working to good extent. Any suggestion on this.
Mark M.
what specifically are you seeing with WorkManager?
Kumar V.
PeriodicWorkRequest doesn't seem to run at all.
Mark M.
does it work if you choose a somewhat shorter period (e.g., 10 minutes instead of 1 day)?
because I would expect PeriodicWorkRequest to work in general
9:05 AM
Kumar V.
No, actually the minimum time for the PeriodicWorkRequest is 15min. I set that, but still it didn't work.
Mark M.
then my guess is that there is something wrong with how you are using it
there certainly can be bugs in the Jetpack libraries
but I would be very surprised if PeriodicWorkRequest simply failed 100% of the time
Kumar V.
Ok, on a general note What would you suggest ? Should I go for WorkManager or AlarmManager
but I would be very surprised if PeriodicWorkRequest simply failed 100% of the time. --> It did fail, I had the app the in the background as well.
Mark M.
if the work needs to be done once in a 24-hour window, and you do not care where in that window the work gets done, use WorkManager
if you need to try for greater control over the precise timing, you can try AlarmManager, or have your server send a high-priority FCM message
to be honest, periodic background work is a mess on modern versions of Android, and I try to steer developers away from having to rely upon it
Kumar V.
Ok. It is a simple thing to configure but it didn't work. Let me do more research and try. Will let you know. I have one last question
Mark M.
Marek already had two questions, so... go ahead with your second question!
Kumar V.
View paste
https://stackoverflow.com/questions/63111091/java-lang-illegalargumentexception-volume-external-primary-not-found-in-android.   

Any help for the above
Mark M.
you filed an SO bump request for that 20 minutes ago, I think
Kumar V.
yes.
Mark M.
and I noticed the question yesterday on Slack and upvoted it
I do not know what is going on there
you might want to edit the question and provide a stack trace, if you have one
Kumar V.
Ok, don't know how it came in the slack.
9:10 AM
Mark M.
sorry, I mean Stack Overflow
(too many communication channels, too little time...)
Kumar V.
you might want to edit the question and provide a stack trace, if you have one --> Will add more
Ha ha, Ok.
Mark M.
off the cuff, this feels like a manufacturer problem, as there should be a primary external storage volume
Kumar V.
Ok. Guess more people are to encounter it soon once they make targetSdk change to 29.
Mark M.
I can put a bounty on the question when SO lets me
but, if you can add the full stack trace, that will help get you an answer
Kumar V.
Ok, will do that.
Mark M.
if I get time later this week, I may try some experiments with some Moto devices and see if I can reproduce the problem
Kumar V.
Ok. That's it Mark. Won't take more of your time. It was nice chatting with you. Would love to discuss more in the future. Thanks a lot.
Mark M.
I have three of these chats a week (for most weeks), so join which ones you can!
9:15 AM
Mark M.
also, there is the Android Developer Discuss board that you can join: https://community.commonsware.com/t/welcome-to-...
in the meantime...
Marek: back to you! do you have another question?
Kumar V.
Sure. Will check.
Marek D.
yes, unprepared one :)
is robolectric still a thing?
Mark M.
I am under the impression that it is getting folded into the Jetpack as part of Project Nitrogen, but I have heard very little about this in the past 15 months or so
personally, I have not been a big Robolectric fan -- I'd prefer to run instrumented tests for things that have a strong tie to the Android SDK
but, I tend to work on smaller projects, where that is practical
if you have 10,000 tests, you cannot afford for too many of them to be instrumented tests instead of unit tests
Marek D.
well robolectric is not that fast either
ofc still faster than instrumentation
Mark M.
when I need to unit test stuff that has Android SDK ties, I tend to just roll custom mocks with Mockito
that may not be the best, but it gets the job done and makes my clients happy
9:20 AM
Mark M.
and I like happy clients :-)
9:20 AM
Marek D.
I am still the only one so I keep asking
I am testing simple thing
I have extension function on my context
to get location permission status
and that is passed up to some other layers
so you can have permission or not
true false
I am writing two tests
but they look the same
just the value differs
there is parametrized test annotation
I can do this
but sometimes I add random boolean
so I write one test
some people say is bad to have random test
or I have a test
that I think value of one parameter is not important
so I also like to give it random value
9:25 AM
Marek D.
if it breaks then my assumption of uniportance breaks as well
but that's a good sign :)
is this really bad approach
Mark M.
the downside of the random-value approach is that your test may not fail 100% of the time
it will fail some percentage of the time, depending on when the random value happens to trigger a failure scenario
testing purists would argue that you need to cover the range of inputs so that you always test the failure scenario
from a more practical standpoint, it may mean that your test fails in somebody else's work
and that somebody may be irritated that your random test failed their CI run or something
so, for example, I was on a project that used Geocoder to get a street address for a GPS coordinate
we found that Geocoder would sometimes change the results it returned, in ways that broke the app (related to address parsing)
I wrote some instrumented tests specifically to try to detect when Google's servers behind Geocoder would change their output format
but this meant that, all of a sudden, tests would fail, having nothing to do with the work other developers were doing
those developers were not very happy with me, even though my tests were doing exactly what we needed them to do
we wound up using @FlakyTest or something to get them out of the CI test runs and only in manual runs
9:30 AM
Mark M.
that's the sort of risk that you take with random values, though in your case it will not be quite as bad as mine
Marek D.
but you found a real case scenario failure
Mark M.
yes, but at a random time and usually affecting all developers, until either we fixed the test or Google changed their servers
in theory, we want tests to say when the code is not working
in practice, we want tests to say when *our changes* to the code is not working
and random inputs, whether directly from test code or, in my case, based on server responses that we don't control, break the "our changes" assumption
the fact that it makes the *app* better may not help make the *team* better
and both have to be taken into account
and with that, I need to wrap up today's chat
the transcript will be posted to https://commonsware.com/office-hours/ shortly
the next chat is Thursday in the 7:30pm US Eastern time slot
have a pleasant day!
Marek D.
bye bye
Marek D.
has left the room
Kumar V.
has left the room
Mark M.
turned off guest access

Saturday, July 25

 

Office Hours

People in this transcript

  • Kumar Velu
  • Marek Defecinski
  • Mark Murphy