- Now that I have officially released my first app, which can be found HERE on the Google Play store. I want to add more features to my app, however, I think the next best step is to add some tests. So, this series is going to be a practical series dedicated to understanding testing in the Android framework. All the information I found for this blog post can be found HERE
- If you are still developing a small application like me, you might think that tests are a waste of time. However, as our apps grow manual testing just can't keep up. Tests give us rapid feed back on failures and failures spotted earlier on are far easier to fix then ones that arise in production. With a good suite of testing we are free to refactor and optimize code to our hearts delight. Also, to create a stable and mature code base tests are mandatory
- When testing in Android our tests will fall into one of 3 categories:
1) Unit tests
2) Integrated tests
3) End-to-end tests
- When writing tests the Google testing team recommends the
Pyramid Principle. Which means 70% of our tests should be
unit, 20% should be
end-to-end. Of course these numbers do not have to be exact.
unit testshould be highly focused and fast, they are tests that exhaustively validate functionality and contracts of each class within our app. As we add and change methods within a particular class, we create and run unit tests against them. Unit tests are recommended to be run as
local unit tests. Which means the tests are going to run on our local machine. So no emulator or physical device required. The down side to these types of tests is since we are not running them in a realistic environment the tests have
low fidelity. Meaning there is still a small chance the code could fail in production. This is because we are usually creating a lot of mocks and fakes for System or third party APIs when using unit tests. do not worry, what one type of test lacks the others make up for.
- In addition to testing each unit of our app by running unit tests, we also validate our app's behaviour from the module level. To do so we write
integration teststhat validate the collaboration and interaction of a group of units. Integrated tests are considered
Instrumented testswhich are meant to be run on a physical device. These tests are less focused so a failure in one might take longer to track down the reason for failing. Since we are using a physical device, less mocks and fakes these tests are considered
higher fidelitythan unit tests. Integrated tests also have slower execution speed . Since our app is assembling multiple components, building them, packaging and shipping them to a device where the tests are run. This obviously is going to take extra time.
- Some examples of when to use integration testing are:
1) Interactions between a view and a view model, like testing a Fragment object, validating layout XML, or evaluating the data-binding logic of a View Model object.
2) Tests in the app's repository layer, which verify that your different data sources and data access objects(DAO, Room database stuff) interact as expected.
3) Testing interactions on a particular screen
4) Multi fragment tests that evaluates a specific area of our app. For this type of test we require a real device because the interactions under test involves multiple UI elements.
- While it is important to tests each class of our app in isolation, it is just as important to validate end-to-end workflows that guide users through multiple modules and features. These types of tests form unavoidable bottlenecks in your code but they offer us the closes validation that our app is production ready. End-to-end tests are also considered
Instrumentedtests, so they will take a longer time to run and also be run on a physical device. It is also recommended that for each end-to-end test we write, we should also write integration tests to verify that each module in the end-to-end tests works as expected.
- A typical project in Android Studio contains two directories for writing tests:
1) androidTest : This directory should contain the test that run on a real or virtual device (Instrumented tests)
1) test : This directory should contain the test that run on your local machine (local unit tests).
- With test driven development the idea is that you start by writing your tests, then implement the code to make those tests pass. Finally, when the tests pass we can put that code into production. TTD forces us to think about the design of our application up front, it makes us think about APIs and the structure of your code. With TTD we are actually write less code because we only write the code to make tests pass. Which makes us create more reliable code more frequently.
Google recommends the testing mantra of
red, green, refactor. which means we start off with a failing test, we implement the code to make it pass and then refactor the code.
That is it for this blog post, next post we will dive deeper and actually write some unit tests
- Thank you for taking the time out of your day to read this blog post of mine. If you have any questions or concerns please comment below or reach out to me on Twitter .