Writing tests is painful, it is not the part of our job we all prefer, however it is mandatory. Indeed, it allows us to guarantee behaviors, features and non-regression. Therefore, since it is such a pain but so important, we need great tools to help us. Truth is one of them.
What is Truth ?
Truth is an assertion/proposition framework appropriate for testing and driven by some extensibility needs.
Truth can be used in place of Fest or AssertJ. But, it goes beyond and gives you sweet tricks to write more elegant and readable tests.
Once again, best way to explain a framework is always code. Let’s imagine we design a Cart class with the following API :
The design is obviously very simple since its only purpose is to illustrate this article.
Now let’s test it. Since we are in 2015, I assume I don’t need to prove why testing framework over JUnit are useful and why you should all be using one.
For all my tests in this article, I will use the following generateCart method :
With Truth, you only need to add the following dependency to your gradle build :
And our tests will look like that :
As we can see our tests are easily read from left to right. There are also some very useful helper methods, especially on collections, to ensure our tests are understandable by most.
Why Truth ?
Now, you could ask yourself : why choose Truth over Fest or AssertJ ?
First of all, Fest does not seem to be maintained anymore. It did not even migrate from GoogleCode that will soon close its doors. So it is not a real option.
About AssertJ, it is a great framework that was originally forked from Fest. I have been using a lot in all my tests. It works perfectly. However, Truth does the exact same things AND more…
Thanks to its architecture, Truth is perfect to use when we want to extend the framework to our custom objects. We can therefore design an API that will add readability and meaning to our code. Let’s see an example with our Cart object. First, we need to write a custom Subject. Subject is a class that represents all the assertions possible on our object.
Now, our tests will look as follow :
As we can see, calls are chainable and since we chose method names, it makes a lot of sense and suits best to the context of our Cart class.
What about Android ? Well, it looks like a perfect case for testing View!
For instance, here is a small Subject I wrote to test a TextView. It’s great because our tests will match perfectly Android API.
Then, I use the TextViewSubject with a new library called screenshot-tests-for-android from Facebook that deals great with testing custom views independently. Here is an example how it works associated with Truth:
So as you may think, we could indeed create a Truth-Android the same way Square implemented AssertJ-android. AssertJ-android supports all the views (and more) from the Android framework. It took time to build it and it is a real success. Right now, I just write ViewSubject according to my needs. However, it would be definitely interesting to create a library to regroup and share them.
Brings failure strategies to testing
Strategies are the other feature that made me try Truth and adopt it. Let’s see what it means.
First, Truth differentiates 3 failure strategies :
The first one we all know is assert. It exists since testing exists. Principle is simple, if we assert something wrong in our test, we stop and fail. That’s what we have been using for all our tests.
The second one is assume. It means that when we assume something in our tests, if it fails our tests is just ignored. It could look useless but it’s very useful on Android especially when dealing with fragmentation. Imagine you want to test a feature of your app that is only available on Lollipop. Then, when you run your instrumentation tests, you want to not run this test on device pre-lollipop. Thanks to assume, the test will be ignored since it is not applicable. Here is an example :
Assume can be used for various use cases such as : my local database is not configured but I still want to execute my unit tests or I want to run some tests specific to Windows or Linux (file system) for instance.
The last strategy available is expect. It means you go through all your assertions even if some fail and you generate a small report at the end. Best use case to my opinion is when you need to assert that a object is correctly filled. You don’t want to fix your test, launch again, fix again, launch again. You want all what is wrong in one time. For instance, I always write a test for testing my Parcelable implementation. With Truth, it does work perfectly :
Finally, it is also possible to implement your own strategy and benefit directly from the rest of the framework. An example Truth’s developers give is to deal better with exception. I never personally needed it but feel free to try.
But be careful…
Truth is great but be careful while using it.
First, it is still in beta version (0.27 at the time of this article). Therefore it may contain some bugs and API may change. However, I am using it since some time now and it is production ready to my opinion.
Secondly, you must be sure you are not abusing the new strategies Truth offers. Indeed, some tests may not run unexpectedly because of assume or developers can feel encourage to tests too many things thanks to expect instead of having very focus and small tests.
I hope this article helps you to see how powerful Truth is and that you will give it a try. Obviously, the next great step would be to code a Truth-Android. Anyone interested ?