官术网_书友最值得收藏!

Mock objects

We have seen the mock objects provided by the Android testing framework in Chapter 1, Getting Started with Testing, and evaluated the concerns about not using real objects to isolate our tests from the surrounding environment.

The next chapter deals with Test-driven Development, and if we were Test-driven Development purists, we can argue about the use of mock objects and be more inclined to use real ones. Martin Fowler calls these two styles the classical and mockist Test-driven Development dichotomy in his great article Mocks aren't stubs, which can be read online at http://www.martinfowler.com/articles/mocksArentStubs.html.

Independent of this discussion, we are introducing mock objects as one of the available building blocks because, sometimes, using mock objects in our tests is recommended, desirable, useful, or even unavoidable.

The Android SDK provides the following classes in the subpackage android.test.mock to help us:

  • MockApplication: This is a mock implementation of the Application class. All methods are non-functional and throw UnsupportedOperationException.
  • MockContentProvider: This is a mock implementation of ContentProvider. All methods are non-functional and throw UnsupportedOperationException.
  • MockContentResolver: This is a mock implementation of the ContentResolver class that isolates the test code from the real content system. All methods are non-functional and throw UnsupportedOperationException.
  • MockContext: This is a mock context class, and this can be used to inject other dependencies. All methods are non-functional and throw UnsupportedOperationException.
  • MockCursor: This is a mock Cursor class that isolates the test code from real Cursor implementation. All methods are non-functional and throw UnsupportedOperationException.
  • MockDialogInterface: This is a mock implementation of the DialogInterface class. All methods are non-functional and throw UnsupportedOperationException.
  • MockPackageManager: This is a mock implementation of the PackageManager class. All methods are non-functional and throw UnsupportedOperationException.
  • MockResources: This is a mock Resources class.

All of these classes have non-functional methods that throw UnsupportedOperationException when used. If you need to use some of these methods, or if you detect that your test is failing with this Exception, you should extend one of these base classes and provide the required functionality.

An overview of MockContext

This mock can be used to inject other dependencies, mocks, or monitors into the classes under test. Extend this class to provide your desired behavior, overriding the correspondent methods. The Android SDK provides some prebuilt mock Context objects, each of which has a separate use case.

The IsolatedContext class

In your tests, you might find the need to isolate the Activity under test from other Android components to prevent unwanted interactions. This can be a complete isolation, but sometimes, this isolation avoids interacting with other components, and for your Activity to still run correctly, some connection with the system is required.

For those cases, the Android SDK provides android.test.IsolatedContext, a mock Context that not only prevents interaction with most of the underlying system but also satisfies the needs of interacting with other packages or components such as Services or ContentProviders.

Alternate route to file and database operations

In some cases, all we need is to be able to provide an alternate route to the file and database operations. For example, if we are testing the application on a real device, we perhaps don't want to affect the existing database but use our own testing data.

Such cases can take advantage of another class that is not part of the android.test.mock subpackage but is part of android.test instead, that is, RenamingDelegatingContext.

This class lets us alter operations on files and databases by having a prefix that is specified in the constructor. All other operations are delegated to the delegating Context that you must specify in the constructor too.

Suppose our Activity under test uses a database we want to control, probably introducing specialized content or fixture data to drive our tests, and we don't want to use the real files. In this case, we create a RenamingDelegatingContext class that specifies a prefix, and our unchanged Activity will use this prefix to create any files.

For example, if our Activity tries to access a file named birthdays.txt, and we provide a RenamingDelegatingContext class that specifies the prefix test, then this same Activity will access the file testbirthdays.txt instead when it is being tested.

The MockContentResolver class

The MockContentResolver class implements all methods in a non-functional way and throws the exception UnsupportedOperationException if you attempt to use them. The reason for this class is to isolate tests from the real content.

Let's say your application uses a ContentProvider class to feed your Activity information. You can create unit tests for this ContentProvider using ProviderTestCase2, which we will be analyzing shortly, but when we try to produce functional or integration tests for the Activity against ContentProvider, it's not so evident as to what test case to use. The most obvious choice is ActivityInstrumentationTestCase2, mainly if your functional tests simulate user experience because you might need the sendKeys() method or similar methods, which are readily available on these tests.

The first problem you might encounter then is that it's unclear as to where to inject a MockContentResolver in your test to be able to use test data with your ContentProvider. There's no way to inject a MockContext either.

This problem will be solved in Chapter 3, Baking with Testing Recipes where further details are provided.

主站蜘蛛池模板: 胶南市| 根河市| 越西县| 海晏县| 石家庄市| 遂川县| 凤凰县| 河源市| 宜宾市| 棋牌| 双城市| 珠海市| 绥芬河市| 当涂县| 邹城市| 平远县| 文化| 黄大仙区| 和田市| 广元市| 许昌县| 淳安县| 金山区| 商洛市| 共和县| 江陵县| 临安市| 宁南县| 霍州市| 玉门市| 信丰县| 望江县| 班戈县| 桐庐县| 伊川县| 朝阳区| 荥阳市| 历史| 汕尾市| 吐鲁番市| 五原县|