In order to use any of the testing utilities please include the
litho-testing package in the
build. Add the following lines to the
dependencies block in the
Litho's testing APIs are exposed through fluid AssertJ methods. They are available as:
- ComponentAssert for assertions that are run against either Component builders or Components.
- LithoViewAssert for assertions against mounted UI hierarchies.
For convenience, LithoAssertions.assertThat
can be statically imported. It hosts all the APIs of
To demonstrate the usage of these APIs consider the following component that displays a like icon and a short description.
To verify the rendering of the text and the icon.
- Create a new test class;
@RunWith(RobolectricTestRunner.class)to the top of the test class.
- Add a
@Rulewhich sets up overrides for Styleables and exposes some useful APIs.
The test class should look like the following:
LithoAssertions exposes AssertJ-style APIs to assert what get rendered by a component. These APIs
will generally layout, mount and render the component before testing the assertions.
There are several more assertions that can be tested using LithoAssertions. To see the entire APIs please checkout its JavaDoc here. These APIs test assertions on the view heirarchy created by the mounted Component. So asserting the presence of a Drawable in a Component will traverse the entire view hierarchy rendered by the Component. Following are some of the assertions provided by LithoAssertions:
When running Litho unit tests, be aware that the native library for Yoga must be loaded which can pose some challenges depending on your build system of choice. With Gradle and Robolectric, for instance, you may run into issues as Robolectric spins up new ClassLoaders for every test suite with a different configuration. The same goes for PowerMock, which prepares the ClassLoaders on a per-suite basis and leaves them in a non-reusable state.
The JVM has two important limitations that are relevant to this:
- A shared library can only ever be loaded once per process.
ClassLoaders do not share information about the libraries loaded.
Because of that, using multiple ClassLoaders for test runs is highly problematic
as every instance will attempt to load Yoga and every but the first will fail with
libyoga.so already loaded in another classloader exception.
The only way to avoid this is by either preventing the use of multiple ClassLoaders or forking the process whenever a new ClassLoader is necessary.
Gradle allows you to limit the number of test classes a process can execute before it is discarded. If you set the number to one, we avoid the ClassLoader reuse:
With Buck, this behavior can be achieved by assigning test targets separate names
as those will result in a parallel process being spun up. Alternatively, you can
per_test as described
Ultimately, depending on your build system and the existing constraints of your project, you may need to adjust the way in which your test runner utilizes ClassLoaders. This is, however, not a problem unique to Litho but an unfortunate consequence of mixing native and Java code in Android projects.