Is there any good sample of an android compose app...
# android
d
Is there any good sample of an android compose app that uses good architecture and is completely unit/instrumented tested? All the sample I've seen have just a part of the tests and fake data only....
j
d
Yeah, I saw those... but they only have a few UI tests... and it doesn't really show how to manage more real-life situations... most of the times apps are much more complex than that, and tests need to have their state initialized to different situations and UI acts accordingly
Those examples just have fake data that creates one situation... unless I'm making a mistake and that UI tests should only really be that simple?
j
The idea of compose, its to separate code in small pieces, to became easier to test, if you have a very large component, maybe you can break it in small pieces and test each one individually.
Avoid send viewmodel to below components, or to sendo lot of data that you dont need, or large objects, it make test harder
d
In those samples they test the whole screen as a single entity, not each piece.
j
you can test whole screen or small pieces, depends of your implementation. What are looking for on unit/instrumented tests?
c
Fwiw @dave08 - you can do an app like level of test using
createAndroidComposeRule
, where you specify the activity you want to test whilst being able to use the rule to evaluate assertions on nodes. You use
createComposeRule
to have the framework spin up an Activity for you to setContent on, which is good for doing things like 'given a compose in this state' type tests. And finally you have
createEmptyComposeRule
which can be used in tests that involve using a mix of both compose and XML views (maybe you have a new compose screen in your pre-existing XML view app). For the
createAndroidComposeRule
you won't be calling
setContent
because the activity you specify will be doing that, so you'll have the same challenges you would have had before compose for injecting your dependencies. For the
createComposeRule
you've got a lot more fine grain control since you get to call
setContent
so often you will just provide a UI state object to your composable you're testing (if you follow the pattern google advocates(?) with a composable that takes a view model and a composable that takes a UI state object). I think pure compose apps wouldn't use the
createEmptyComposeRule
but I could be wrong. If you use test robots, you'll find yourself passing in a compose test rule of some description to be able to do the node resolution and assertion (whilst before you may have use onView()). Beyond that, you might find that you can't target a particular node you're interesting in, in which case you'll end up having to use
modifier.testTag(...)
as a way to be able to locate the element in your test by the tag instead.
Hope this helps
d
Thanks alot @czuckie for the elaborate explanation! Right now I have a mixed xml-compose app (I'm currently slowly migrating to compose), so how would I handle setups with
createEmptyComposeRule
?
And how would I make it in a way that they could eventually be migrated to
createComposeRule
type tests...?
c
so if you had ActivityA as an XML activity that contained a compose view, I'd use
ActivityScenario<ActivityA>
to spin it up as well as a
createEmptyComposeRule
, but I might have a test that used
createComposeRule
that I'd use to test the ComposeView on it's own
d
And you would still use the setContent in the scenario's onActivity to set the compose view and test it there too?
(If I understand properly... I was looking at it very shortly...)
c
with the ActivityScenario, you'd launch your activity that would inflate its own XML layout and would setContent on a ComposeView itself, but for the individual composable test, you'd call
setContent
on the rule created with
createComposeRule
as that rule handles creating some kind of activity to host a ComposeView on your behalf
j
You might think of testing a partially-compose activity like this: Write tests using
ActivityScenario
and Espresso view matchers as before. But you'll run into problems when trying to match Composables with espresso view matchers - they don't. So for that, also add an
EmptyComposeRule
as a
@Rule
to the test - it just needs to be there, so its registry setup will run. Now you can use the composeRule to do view matching and assertions on the composables.
There is no need to somehow explicitly register the content-under-test with the compose rule, it will find it by itself. (That part had me quite confused a few weeks ago.)
d
Btw, it seems like his project DOES have complete tests and good architecture...
j
Because there, he really want to test "only" the Composable - note that the activityScenario launches a
ComponentActivity
, not any specific activity of the app. If I understand correctly, this is to workaround some issues with the test lifecycle that you get forced into because ComposeRules are Rules and must be used as Rules. (I.e., observe how there's both
ActivityTestRule
and
ActivityScenario
- the former taking away some boilerplate for a common case and a lot of flexibility to handle other cases. There's no compose equivalent to
ActivityScenario
.)
And yes, this particular post was both very helpful and very confusing to me 😉
d
Wow, thanks for the explanation! I'm pretty new to compose, and there's quite a bit to learn...
Another point, I guess there's really no way to migrate tests for xml views to compose easily... I would have expected some kind of compat library to exchange implementations while migrating...
The real problem might be locating elements I guess, since in compose there aren't really id's anymore?
(Again, I'm still new and just trying to get an initial understanding, even though I really didn't delve into the subject enough yet... I don't really want to start with the wrong tools and discover that in the middle...)
j
• auto migration: not that I know of, but most of it is pretty mechanic. • locating elements: that's what the compose rule is for - you'll go e.g.
composeTestRule.onNodeWithText(...)
- if those don't work, the ultimate escape hatch/id-matching equivalent can be found in
Modifier.semantics
👍🏼 1
c
Modifier.testTag is the get out of jail free card
though it kills me to have 'test' appear in production code 😂
d
🙈
c
fun Modifier.definitelyNotATestTag(tag: String) = this.testTag(tag)
eases the pain /s
😇 2
a
As a more complicated example, https://github.com/android/nowinandroid has unit tests and instrumented tests if you haven’t seen it yet
👍🏼 1
d
Also seems interesting, thanks!
206 Views