Accessibility Adding features to support users with impaired vision, mobility, or hearing
TalkBack TalkBack is an Android screen reader made by Google. It speaks out the contents of a screen based on what the user is doing. The emulator does not support TalkBack, so you have to have an Android device to deploy onto. To enable TalkBack, launch Settings and press Accessibility. Press on TalkBack under the Services heading. Then press the switch near the top right of the screen to turn TalkBack on.
A dialog asking for permission to access certain information, e.g. observing the user s actions, altering certain settings, such as turning on Explore by Touch. Green outlines highlight UI elements that have accessibility focus. Explore by Touch speaks information about an item immediately after it is pressed, assuming that the item specifies information TalkBack can read. Swiping moves the focus
Making Non-Text Elements Readable Normally, non-text items will result in TalkBack announcing Button unlabelled. Double-tap to activate. This can be changed by, e.g. adding a content description to an ImageButton. Add content description strings (res/values/strings.xml): <resources>... <string name="crime_details_label">details</string> <string name="crime_solved_label">solved</string> <string name="crime_photo_button_description">take photo of crime scene</string> <string name="crime_photo_no_image_description"> Crime scene photo (not set) </string> <string name="crime_photo_image_description">crime scene photo (set)</string>... </resources>
Descriptions for ImageView and ImageButton: <ImageView android:id="@+id/crime_photo" android:layout_width="80dp" android:layout_height="80dp" android:background="@android:color/darker_gray" android:croptopadding="true" android:scaletype="centerinside" android:contentdescription="@string/crime_photo_no_image_description" /> <ImageButton android:id="@+id/crime_camera" android:layout_width="match_parent" android:layout_height="wrap_content" android:src="@android:drawable/ic_menu_camera" android:contentdescription="@string/crime_photo_button_description" />
Dynamic Content Descriptions public class CrimeFragment extends Fragment {... private void updatephotoview() { if (mphotofile == null!mphotofile.exists()) { mphotoview.setimagedrawable(null); mphotoview.setcontentdescription( getstring(r.string.crime_photo_no_image_description)); else {... mphotoview.setimagebitmap(bitmap); mphotoview.setcontentdescription( getstring(r.string.crime_photo_image_description));
Unit Testing JUnit
Two Types of Unit Tests Local unit tests Located at module-name/src/test/java/. These tests run on the local JVM and do not have access to functional Android framework APIs. Instrumented tests Located at module-name/src/androidtest/java/. These are all tests that must run on an Android hardware device or an Android emulator. Instrumented tests are built into an APK that runs on the device alongside your app under test. The system runs your test APK and your app under tests in the same process, so your tests can invoke methods and modify fields in the app, and automate user interaction with your app.
Local vs Instrumental
Testing
JUnit Write a unit or integration test class as a JUnit 4 test class. The framework offers a convenient way to perform common setup, teardown, and assertion operations in your test. A basic JUnit 4 test class is a Java class that contains one or more test methods. Test methods begins with the @Test annotation and contains the code to exercise and verify a single functionality, i.e., a logical unit in the component to be tested. The following snippet shows an example JUnit 4 integration test that uses the Espresso APIs to perform a click action on a UI element, then checks to see if an expected string is displayed.
Integration Test @RunWith(AndroidJUnit4.class) @LargeTest public class MainActivityInstrumentationTest { @Rule public ActivityTestRule mactivityrule = new ActivityTestRule<>( MainActivity.class); @Test public void sayhello(){ onview(withtext("say hello!")).perform(click()); onview(withid(r.id.textview)).check(matches(withtext("hello, World!")));
JUnit Annotations @Before: Use this annotation to specify a block of code that contains test setup operations. The test class invokes this code block before each test. You can have multiple @Before methods but the order in which the test class calls these methods is not guaranteed. @After: This annotation specifies a block of code that contains test tear-down operations. The test class calls this code block after every test method. You can define multiple @After operations in your test code. Use this annotation to release any resources from memory.
JUnit Annotations @Test: Use this annotation to mark a test method. A single test class can contain multiple test methods, each prefixed with this annotation. @Rule: Rules allow you to flexibly add or redefine the behaviour of each test method in a reusable way. In Android testing, use this annotation together with one of the test rule classes that the Android Testing Support Library provides, such as ActivityTestRule or ServiceTestRule.
JUnit Annotations @BeforeClass: Use this annotation to specify static methods for each test class to invoke only once. This testing step is useful for expensive operations such as connecting to a database. @AfterClass: Use this annotation to specify static methods for the test class to invoke only after all tests in the class have run. This testing step is useful for releasing any resources allocated in the @BeforeClass block. @Test(timeout=): Some annotations support the ability to pass in elements for which you can set values. For example, you can specify a timeout period for the test. If the test starts but does not complete within the given timeout period, it automatically fails. You must specify the
Local Testing In the app's top-level build.gradle file, we need to specify these libraries as dependencies: dependencies { // Required -- JUnit 4 framework testcompile 'junit:junit:4.12' // Optional -- Mockito framework testcompile 'org.mockito:mockito-core:1.10.19' As a basic JUnit 4 test class, create a Java class that contains one or more test methods. A test method begins with the @Test annotation and contains the code to exercise and verify a single functionality in the component that you want to test.
Example The test method emailvalidator_correctemailsimple_returnstr ue verifies that the isvalidemail() method in the app under test returns the correct result. import org.junit.test; import java.util.regex.pattern; import static org.junit.assert.assertfalse; import static org.junit.assert.asserttrue; public class EmailValidatorTest { @Test public void emailvalidator_correctemailsimple_returnstrue() { assertthat(emailvalidator.isvalidemail("name@email.com"), is(true));...
Testing and Gradle The Android Plug-in for Gradle executes local unit tests against a modified version of the android.jar library, which does not contain any actual code. Method calls to Android classes from the unit test throw an exception. This is to make sure you test only your code and don t depend on any particular behaviour of the Android platform This can be changed by mocking.
Mocking an object To add a mock object to a local unit test: 1. Include the Mockito library dependency in build.gradle 2. At the beginning of the unit test class definition, add @RunWith(MockitoJUnitRunner.class) annotation. This annotation tells the Mockito test runner to validate that the usage of the framework is correct and simplifies the initialisation of mock objects. 3. To create a mock object for an Android dependency, add the @Mock annotation before the field declaration. 4. To stub the behaviour of the dependency, specify a condition and return value when the condition is met by using the when() and thenreturn() methods. With Mockito, you can configure mock objects to return some specific value when invoked.
Importing Mockito Select the Dependencies tab at the top of the screen, click the + button; Select the org.mockito:mockito-core dependency and click OK; Repeat for Hamcrest, searching for hamcrest-junit and selecting org.hamcrest:hamcrest-junit
Example: a mock Context object import static org.hamcrest.matcherassert.assertthat; import static org.hamcrest.corematchers.*; import static org.mockito.mockito.*; import org.junit.test; import org.junit.runner.runwith; import org.mockito.mock; import org.mockito.runners.mockitojunitrunner; import android.content.sharedpreferences; @RunWith(MockitoJUnitRunner.class) public class UnitTestSample { private static final String FAKE_STRING = "HELLO WORLD"; @Mock Context mmockcontext; @Test public void readstringfromcontext_localizedstring() { // Given a mocked Context injected into the object under test... when(mmockcontext.getstring(r.string.hello_word)).thenreturn(fake_string); ClassUnderTest myobjectundertest = new ClassUnderTest(mMockContext); //...when the string is returned from the object under test... String result = myobjectundertest.gethelloworldstring(); //...then the result should be the expected one. assertthat(result, is(fake_string));
Creating a test class To write unit tests we use a testing framework. The framework makes it easier to write and run a suite of tests together and see their output in Android Studio. JUnit is used as a testing framework on Android and has convenient integrations into Android Studio. Create a JUnit tests class. In SoundViewModel.java type Ctrl+Shift+T to make Android Studio navigate to a test class associated with the current class. If there is no test class, we are given the option to create a new one. Unit tests go in folder test
Setting up the test
Writing tests A test class A mock BeatBox class public class SoundViewModelTest { private BeatBox mbeatbox; private Sound msound; private SoundViewModel msubject; @Before public void setup() throws Exception { mbeatbox = mock(beatbox.class); msound = new Sound("assetPath"); msubject = new SoundViewModel(mBeatBox); msubject.setsound(msound); @Before Test subject Testing the title property public void setup() throws Exception { mbeatbox = mock(beatbox.class); msound = new Sound("assetPath"); msubject = new SoundViewModel(mBeatBox); msubject.setsound(msound); @Test public void exposessoundnameastitle() { assertthat(msubject.gettitle(), is(msound.getname()));