Profile cover photo
Profile photo
Matthias Käppler
I, code.
I, code.

Matthias Käppler's posts

Post has shared content

Post has attachment
The recording of my GOTO talk is now available 

Post has attachment
In case you missed it: we published part 2 of our story combating Android's method limit. This one covers MultiDex and monitoring build health. Leave us feedback! 

Post has shared content
I was home with a cold all weekend, so I wrote up the Android threading talk I presented earlier this year. (It's a trap. It's actually about RxJava.)


Post has shared content

Post has shared content
My verdict for unit testing on Android: it's 2015, and it's still somewhat broken.

Perhaps not as broken as it used to be, but still broken in some really fundamental ways.

We've been using Robolectric 1 for a very long time in the SoundCloud app and built up a substantial test suite (cloc counts about 73K lines of test code), but building something that mission critical on legacy software is of course a ticking time bomb.

After all the recent fuss about improvements in Android unit testing, I spent quite some time evaluating the different approaches to select the one that would offer us the greatest benefit with the least amount of friction (side note: it's 2015--why does unit testing require time to make it work? It should be as straight forward as drinking a cup of coffee.) I have to say I left disappointed; some things are broken by design, others are just broken. Brief summary:

Variation 1: Running unit tests on a connected device
The obvious benefit here is one of confidence: you are instrumenting your code against an actual system image, with the same VM that will actually run your code in production. It's the real deal. In the past, this approach wasn't exactly a great solution for numerous reasons (poor emulator performance, impossible to use mocking libraries, no JUnit 4 support to name the biggest ones.)
This has gotten better: we have a JUnit 4 runner now [0], we have DexMaker (a bytecode backend for Dalvik) [1], and we have Genymotion, but one of the major problems still exists: the platform JAR is full of final classes and methods, so you either have to write your tests to take that into account, or move your code as far away from the platform as possible; which is likely a good idea anyway [2], but induces the cost of introducing abstractions that might purely exist for testability.

Variation 2a: Running unit tests on the JVM (not using Robolectric)
With the arrival of "experimental unit testing support" (now not experimental anymore), we can now run tests from src/test/java using ordinary test runners. Since it's an ordinary Java unit test, you can use ordinary test setups and libraries, too. Rejoice! However, this approach still has several drawbacks.
Although a Gradle task has been introduced that strips the platform JAR of all finals and method bodies, as soon as your test subject is somehow entangled with the platform, like when using Intents or Bundles, your test will likely fail, since all these classes are stubbed out. Since Intent or Bundle are foundational platform types, they typically don't appear as collaborators in constructors, so you either have to come up with awkward indirections ("intent providers") or, again, move your code as far away from the platform as possible (again, see [2]) You will also likely end up wiring a lot of mocks in your tests, making your tests hard to read and understand (after all, that's one reason why Robolectric was initially created)
A final annoyance: why on Earth am I not able to see both unit tests and acceptance tests at the same time? Due to some idiosyncratic behavior in either AS or Gradle's Android plugin, only one Gradle source set containing tests can be active at once, as chosen by the "test artifact" setting in your build flavors. So unit tests are piggy backed on a system that it wasn't really built for, and it means that any refactorings you apply to one source set will not apply to the other source set, which is just asking for trouble. I hope this is only temporary and will get addressed with future versions of the AS (I assume it's a shortcoming of AS.)

Variation 2b: Running unit tests on the JVM (using Robolectric)
After we tried so hard to move away from Robolectric 1, we closed the circle by opting for... Robolectric 3. At SoundCloud we decided it was the most preferable solution of the three. It comes with all the benefits of running a normal JUnit test, but doesn't penalize you for writing tests for classes that use things like Bundles directly. Unfortunately (--or fortunately?), the higher you go up in the layers, the more difficult it is (still) to unit test something, which is probably a signal that even with a powerful tool like Robolectric, you should test code that is close to the UI sparingly (if at all), and focus on testing presentation /logic/, business rules, and anything beneath. For instance, Robolectric hasn't quite figured out timing yet, so things like animations steered by a presenter might fail. [3] Overall it's a huge step forward from the initial release though, and comes nicely modularized. By combining test rules and base classes for your tests, you can also keep much of the setup boiler plate out of your actual test cases, so that you don't couple yourself too much to any RL specifics.


Post has shared content

Post has attachment
T-6 days!

More photos from Kelly, our amazing office manager who made it all happen:

Disclaimer: ping-pong table is still in the box, an obvious omission on the pictures ;-)

Post has shared content
Gradle Plugin 0.11.1 was just pushed. It should be available shortly depending on mirror replication.

release notes:

- Fix issue with artifact depending on android.jar artifact on MavenCentral. (this is the ApiVersion to Integer casting error)
- Fix issue with missing custom namespace declaration in generated manifest.
- Fix issue with validation of permission group in manifest merger.

Post has shared content
Just forget about the hard work to give credits. AboutLibraries does everything for you. Including the Activity or Fragment!

More information here:

To the background:
Everyone (or at least many of us) always try to give credits to those people who create awesome libraries for us (so we don't have to get crazy, just to implement an easy function :D). But it was always very time consuming to copy and paste the required information, create a layout, manage the information, create an activity / fragment and include in your app.
With the time many of us stop to include those information in their apps because they just don't want to invest any time in it.
So i've created this lib. You can use it to just get the information (if you still want to build a custom activty) or you can just call the included activity and let the lib do all the hard work for you.
Right now just a few libs include the information file, and the lib itself also just includes a few information.

You can help and contribute by creating the information file for the libs you use and love. Create a pull-request and let the dev itself include it in his library (so it's even easier for you and everyone else to use) or if the lib isn't maintained anymore create a pull-request at the AboutLibraries repository so i can include it.

Enough words. Just check out the repository and have a nice evening and weekend! :D 
Wait while more posts are being loaded