[关闭]
@mSolo 2015-04-15T22:46:03.000000Z 字数 10470 阅读 1998

Android 测试学习笔记(二)

Android 测试 TDD 持续集成


Android 单元测试

Mocking applications and preferences

Mocking contexts

  1. public class TemperatureConverterApplicationTests extends
  2. ApplicationTestCase<TemperatureConverterApplication> {
  3. public TemperatureConverterApplicationTests() {
  4. this("TemperatureConverterApplicationTests");
  5. }
  6. public TemperatureConverterApplicationTests(String name) {
  7. super(TemperatureConverterApplication.class);
  8. setName(name);
  9. }
  10. public void testSetAndRetreiveDecimalPlaces() {
  11. RenamingMockContext mockContext = new RenamingMockContext(getContext());
  12. setContext(mockContext);
  13. createApplication();
  14. TemperatureConverterApplication application = getApplication();
  15. application.setDecimalPlaces(3);
  16. assertEquals(3, application.getDecimalPlaces());
  17. }
  18. }
  1. public class TemperatureConverterApplication extends Application {
  2. private static final int DECIMAL_PLACES_DEFAULT = 2;
  3. private static final String KEY_DECIMAL_PLACES = ".KEY_DECIMAL_PLACES";
  4. private SharedPreferences sharedPreferences;
  5. @Override
  6. public void onCreate() {
  7. super.onCreate();
  8. sharedPreferences = PreferenceManager.getDefaultSharedPreferences(this);
  9. }
  10. public void setDecimalPlaces(int places) {
  11. Editor editor = sharedPreferences.edit();
  12. editor.putInt(KEY_DECIMAL_PLACES, places);
  13. editor.apply();
  14. }
  15. public int getDecimalPlaces() {
  16. return sharedPreferences.getInt(KEY_DECIMAL_PLACES, DECIMAL_PLACES_DEFAULT);
  17. }
  18. }

Testing activites

  1. public class ForwardingActivity extends Activity {
  2. private static final int GHOSTBUSTERS = 999121212;
  3. @Override
  4. protected void onCreate(Bundle savedInstanceState) {
  5. super.onCreate(savedInstanceState);
  6. setContentView(R.layout.activity_forwarding);
  7. View button = findViewById(R.id.forwarding_go_button);
  8. button.setOnClickListener(new View.OnClickListener() {
  9. @Override
  10. public void onClick(View v) {
  11. Intent intent = new Intent("tel:" + GHOSTBUSTERS);
  12. startActivity(intent);
  13. finish();
  14. }
  15. });
  16. }
  17. }
  1. public class ForwardingActivityTest extends
  2. ActivityUnitTestCase<ForwardingActivity> {
  3. private Intent startIntent;
  4. public ForwardingActivityTest() {
  5. super(ForwardingActivity.class);
  6. }
  7. @Override
  8. protected void setUp() throws Exception {
  9. super.setUp();
  10. Context context = getInstrumentation().getContext();
  11. startIntent = new Intent(context, ForwardingActivity.class);
  12. }
  13. public void testLaunchingSubActivityFiresIntentAndFinishesSelf() {
  14. Activity activity = startActivity(startIntent, null, null);
  15. View button = activity.findViewById(R.id.forwarding_go_button);
  16. button.performClick();
  17. assertNotNull(getStartedActivityIntent());
  18. assertTrue(isFinishCalled());
  19. }
  20. public void testExampleOfLifeCycleCreation() {
  21. Activity activity = startActivity(startIntent, null, null);
  22. getInstrumentation().callActivityOnStart(activity);
  23. getInstrumentation().callActivityOnResume(activity);
  24. // 进行测试
  25. getInstrumentation().callActivityOnPause(activity);
  26. // 进行测试
  27. getInstrumentation().callActivityOnStop(activity);
  28. // At this point, you could confirm that the activity has shut itself down appropriately,
  29. // or you could use a Mock Context to confirm that your activity has released any
  30. // system resources it should no longer be holding.
  31. // ActivityUnitTestCase.tearDown() is always automatically called
  32. // and will take care of calling onDestroy().
  33. }
  34. }

Testing files, databases, and content providers

  1. textView = (TextView) findViewById(R.id.mock_text_view);
  2. try {
  3. FileInputStream fis = openFileInput(FILE_NAME);
  4. textView.setText(convertStreamToString(fis));
  5. } catch (FileNotFoundException e) {
  6. textView.setText("File not found");
  7. }
  1. $ adb shell
  2. $ echo "This is real data" > data/data/com.blundell.tut/files/my_file.txt
  3. $ echo "This is *MOCK* data" > /data/data/com.blundell.tut/files/test.my_file.txt
  1. public class MockContextExampleTest
  2. extends ActivityUnitTestCase<MockContextExampleActivity> {
  3. private static final String PREFIX = "test.";
  4. private RenamingDelegatingContext mockContext;
  5. public MockContextExampleTest() {
  6. super(MockContextExampleActivity.class);
  7. }
  8. @Override
  9. protected void setUp() throws Exception {
  10. super.setUp();
  11. mockContext = new RenamingDelegatingContext(getInstrumentation().getTargetContext(), PREFIX);
  12. mockContext.makeExistingFilesAndDbsAccessible();
  13. }
  14. public void testSampleTextDisplayed() {
  15. setActivityContext(mockContext); // must called before startActivity()
  16. startActivity(new Intent(), null, null);
  17. assertEquals("This is *MOCK* data\n", getActivity().getText());
  18. }
  19. }

Testing exceptions

  1. public void testExceptionForLessThanAbsoluteZeroC() {
  2. try {
  3. TemperatureConverter.celsiusToFahrenheit(ABSOLUTE_ZERO_C - 1);
  4. fail();
  5. } catch (InvalidTemperatureException ex) {
  6. // do nothing we expect this exception!
  7. }
  8. }

Testing local and remote services

  1. public class DummyServiceTest extends ServiceTestCase<DummyService> {
  2. public DummyServiceTest() {
  3. super(DummyService.class);
  4. }
  5. public void testBasicStartup() {
  6. Intent startIntent = new Intent();
  7. startIntent.setClass(getContext(), DummyService.class);
  8. startService(startIntent);
  9. }
  10. public void testBindable() {
  11. Intent startIntent = new Intent();
  12. startIntent.setClass(getContext(), DummyService.class);
  13. bindService(startIntent);
  14. }
  15. }

Extensive use of mock objects - About Mockito

  1. dependencies {
  2. androidTestCompile('com.google.dexmaker:dexmaker-mockito:1.1')
  3. }
  4. packagingOptions {
  5. exclude 'META-INF/LICENSE'
  6. exclude 'folder/duplicatedFileName'
  7. }

Exmaple

  1. public void testTextChangedFilterWorksForCharacterInput() {
  2. assertEditNumberTextChangeFilter("A1A", "1");
  3. }
  4. /**
  5. * @param input the text to be filtered
  6. * @param output the result you expect once the input has been filtered
  7. */
  8. private void assertEditNumberTextChangeFilter(String input, String output) {
  9. int lengthAfter = output.length();
  10. TextWatcher mockTextWatcher = mock(TextWatcher.class);
  11. editNumber.addTextChangedListener(mockTextWatcher);
  12. editNumber.setText(input);
  13. verify(mockTextWatcher).afterTextChanged(editableCharSequenceEq(output));
  14. verify(mockTextWatcher).onTextChanged(charSequenceEq(output), eq(0), eq(0), eq(lengthAfter));
  15. verify(mockTextWatcher).beforeTextChanged(charSequenceEq(""), eq(0), eq(0), eq(lengthAfter));
  16. }
  1. class CharSequenceMatcher extends ArgumentMatcher<CharSequence> {
  2. private final CharSequence expected;
  3. static CharSequence charSequenceEq(CharSequence expected) {
  4. return argThat(new CharSequenceMatcher(expected));
  5. }
  6. CharSequenceMatcher(CharSequence expected) {
  7. this.expected = expected;
  8. }
  9. @Override
  10. public boolean matches(Object actual) {
  11. return expected.toString().equals(actual.toString());
  12. }
  13. @Override
  14. public void describeTo(Description description) {
  15. description.appendText(expected.toString());
  16. }
  17. }

Testing views in isolation

  1. public class FocusTest extends AndroidTestCase {
  2. private FocusFinder focusFinder;
  3. private ViewGroup layout;
  4. private Button leftButton;
  5. private Button centerButton;
  6. private Button rightButton;
  7. @Override
  8. protected void setUp() throws Exception {
  9. super.setUp();
  10. focusFinder = FocusFinder.getInstance();
  11. Context context = getContext(); // inflate the layout
  12. LayoutInflater inflater = LayoutInflater.from(context);
  13. layout = (ViewGroup) inflater.inflate(R.layout.view_focus, null);
  14. // manually measure it, and lay it out
  15. layout.measure(500, 500);
  16. layout.layout(0, 0, 500, 500);
  17. leftButton = (Button) layout.findViewById(R.id.focus_left_button);
  18. centerButton = (Button) layout.findViewById(R.id.focus_center_button);
  19. rightButton = (Button) layout.findViewById(R.id.focus_right_button);
  20. }
  21. public void testGoingRightFromLeftButtonJumpsOverCenterToRight() {
  22. View actualNextButton = focusFinder.findNextFocus(layout, leftButton, View.FOCUS_RIGHT);
  23. String msg = "right should be next focus from left";
  24. assertEquals(msg, this.rightButton, actualNextButton);
  25. }
  26. public void testGoingLeftFromRightButtonGoesToCenter() {
  27. View actualNextButton = focusFinder.findNextFocus(layout, rightButton, View.FOCUS_LEFT);
  28. String msg = "center should be next focus from right";
  29. assertEquals(msg, this.centerButton, actualNextButton);
  30. }
  31. }

Testing parsers

  1. public class ParserExampleActivityTest extends AndroidTestCase {
  2. public void testParseXml() throws IOException {
  3. InputStream assetsXml = getContext().getAssets().open("my_document.xml");
  4. String result = parseXml(assetsXml);
  5. assertNotNull(result);
  6. }
  7. }

 Testing for memory usage

  1. public void assertNotInLowMemoryCondition() {
  2. //Verification: check if it is in low memory
  3. ActivityManager.MemoryInfo mi = new ActivityManager.MemoryInfo();
  4. ((ActivityManager)getActivity().getSystemService(Context.ACTIVITY_SERVICE)).getMemoryInfo(mi);
  5. assertFalse("Low memory condition", mi.lowMemory);
  6. }
  7. private String captureProcessInfo() {
  8. InputStream in = null;
  9. try {
  10. String cmd = "ps";
  11. Process p = Runtime.getRuntime().exec(cmd);
  12. in = p.getInputStream();
  13. Scanner scanner = new Scanner(in);
  14. scanner.useDelimiter("\\A");
  15. return scanner.hasNext() ? scanner.next() : "scanner error";
  16. } catch (IOException e) {
  17. fail(e.getLocalizedMessage());
  18. } finally {
  19. if (in != null) {
  20. try {
  21. in.close();
  22. } catch (IOException ignore) {
  23. }
  24. }
  25. }
  26. return "captureProcessInfo error";
  27. }
  28. // Log.d(TAG, captureProcessInfo());
  1. D/ActivityTest(1): USER PID PPID VSIZE RSS WCHAN PC State NAME
  2. D/ActivityTest(1): root 1 0 312[KB] 220 c009b74c 0000ca4c S /init
  3. D/ActivityTest(1): root 2 0 0 0 c004e72c 00000000 S kthreadd
  4. D/ActivityTest(1): root 3 2 0 0 c003fdc8 00000000 S ksoftirqd/0
  5. D/ActivityTest(1): root 4 2 0 0 c004b2c4 00000000 S events/0
  6. D/ActivityTest(1): root 5 2 0 0 c004b2c4 00000000 S khelper
  7. D/ActivityTest(1): root 6 2 0 0 c004b2c4 00000000 S suspend
  8. D/ActivityTest(1): root 7 2 0 0 c004b2c4 00000000 S kblockd/0
  9. D/ActivityTest(1): root 8 2 0 0 c004b2c4 00000000 S cqueue
  10. D/ActivityTest(1): root 9 2 0 0 c018179c 00000000 S kseriod

Testing with Espresso

  1. dependencies {
  2. // other dependencies
  3. androidTestCompile('com.android.support.test.espresso:espresso-core:2.0')
  4. }
  5. android {
  6. defaultConfig {
  7. // other configuration
  8. testInstrumentationRunner "android.support.test.runner.AndroidJUnitRunner"
  9. }
  10. // Annoyingly there is a overlap with Espresso dependencies at the moment
  11. // add this closure to fix internal jar file name clashes
  12. packagingOptions {
  13. exclude 'LICENSE.txt'
  14. }
  15. }
  1. public class ExampleEspressoTest extends
  2. ActivityInstrumentationTestCase2<EspressoActivity> {
  3. public ExampleEspressoTest() {
  4. super(EspressoActivity.class);
  5. }
  6. @Override
  7. public void setUp() throws Exception {
  8. getActivity();
  9. }
  10. public void testClickingButtonShowsImage() {
  11. Espresso.onView(ViewMatchers.withId(R.id.espresso_button_order))
  12. .perform(ViewActions.click());
  13. Espresso.onView(ViewMatchers.withId(R.id.espresso_imageview_cup)) .check(ViewAssertions.matches(ViewMatchers.isDisplayed()));
  14. }
  15. public void testClickingButtonShowsImage() {
  16. Espresso.onView(withId(R.id.espresso_button_order)).perform(click());
  17. Espresso.onView(withId(R.id.espresso_imageview_cup)).check(matches(isDisplayed()));
  18. }
  19. }
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注