Instrumentation Tests are about testing different app components working together to achieve a certain functionality such as, in the app provided, logging in. Since this is a high level overview it would make things easy to find tests for certain high level feature which would definitely contain more granular tests regarding that feature such as entering an invalid email format in the email field and so on. So personally I would think of the instrumentation tests structured as such:
androidTest
\--- java
\--- com.example.myapp
+--- login
| +--- LoginTest (Class, Scenario 1 of high level feature, ex: already signed up login)
| | +--- valid_email_login (method)
| | +--- invalid_email_login (method)
| | \--- no_internet_connection (method)
| \--- AnotherLoginTest (Class, Scenario 2 of high level feature, ex: create new account login)
| \--- test_for_scenario_2 (method)
\--- another_high_level_feature (and so on...)
That way the tests can be easily understood and built upon or changed as the code changes.
With unit tests, testing is made on a single (hence so-called unit) component of the app such as the LoginPresenter
. Usually the test would mock up all needed dependencies for the component (probably using Mockito
or other kind of mock injection) and verify that the component is behaving properly as per logic. Note that for best practices, unit tests don't need a device/emulator or activity related dependency like Context
and hence the reason why an architecture like in your example MVP is needed to be able to carry out unit testing on your local machine (PC or laptop). But this does not stop you from creating unit tests within the androidTest
folder, specifically in cases where you're testing a component that needs a device or emulator for hardware related component testing like NFC or GPS, etc...
So in that case I would personally end up with something like this:
src
+--- androidTest
| |--- java
| \--- com.example.myapp
| +--- unit
| \--- (unit\component related tests that need device\emulator go here)
| \--- instrumentation (components working together related tests go here)
| +--- login
| | +--- LoginTest (Class, Scenario 1 of high level feature, ex: already signed up login)
| | | +--- valid_email_login (method)
| | | +--- invalid_email_login (method)
| | | \--- no_internet_connection (method)
| | \--- AnotherLoginTest (Class, Scenario 2 of high level feature, ex: create new account login)
| | \--- test_for_scenario_2 (method)
| \--- another_high_level_feature (and so on...)
\--- test
|--- java
\--- com.example.myapp (unit\component related tests that don't need device\emulator go under here)
+--- presenters
| +--- LoginPresenterTest
| | +--- view_loading (method)
| | +--- disable_views_when_loading (method)
| | \--- another_unit_test (method)
| \--- AnotherPresenterTest
\--- models (and so on...)
With regards to different variants that your app consists of, the Android Gradle Plugin provides you with a command to figure out where to place variant dependent tests. Simply run gradlew :app:sourceSets
in your project root directory and you'll get for every variant (whether its for test
, androidTest
or none) the directory structure for it. Check out this link for more info: Configure Build Variants. Also don't forget to checkout @Rule
in JUnit
while building your tests.
As a final wrap up, a link to a good Codelab example to illustrate most of the above: Android Testing Codelab