Home | History | Annotate | Download | only in test
      1 /*
      2  * Copyright (C) 2007 The Android Open Source Project
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 
     17 package android.test;
     18 
     19 import android.content.ContentProvider;
     20 import android.content.ContentResolver;
     21 import android.content.Context;
     22 import android.content.res.Resources;
     23 import android.test.mock.MockContext;
     24 import android.test.mock.MockContentResolver;
     25 import android.database.DatabaseUtils;
     26 
     27 import java.io.File;
     28 
     29 /**
     30  * This test case class provides a framework for testing a single
     31  * {@link ContentProvider} and for testing your app code with an
     32  * isolated content provider. Instead of using the system map of
     33  * providers that is based on the manifests of other applications, the test
     34  * case creates its own internal map. It then uses this map to resolve providers
     35  * given an authority. This allows you to inject test providers and to null out
     36  * providers that you do not want to use.
     37  * <p>
     38  *      This test case also sets up the following mock objects:
     39  * </p>
     40  * <ul>
     41  *      <li>
     42  *          An {@link android.test.IsolatedContext} that stubs out Context methods that might
     43  *          affect the rest of the running system, while allowing tests to do real file and
     44  *          database work.
     45  *      </li>
     46  *      <li>
     47  *          A {@link android.test.mock.MockContentResolver} that provides the functionality of a
     48  *          regular content resolver, but uses {@link IsolatedContext}. It stubs out
     49  *          {@link ContentResolver#notifyChange(Uri, ContentObserver, boolean)} to
     50  *          prevent the test from affecting the running system.
     51  *      </li>
     52  *      <li>
     53  *          An instance of the provider under test, running in an {@link IsolatedContext}.
     54  *      </li>
     55  * </ul>
     56  * <p>
     57  *      This framework is set up automatically by the base class' {@link #setUp()} method. If you
     58  *      override this method, you must call the super method as the first statement in
     59  *      your override.
     60  * </p>
     61  * <p>
     62  *     In order for their tests to be run, concrete subclasses must provide their own
     63  *     constructor with no arguments. This constructor must call
     64  *     {@link #ProviderTestCase2(Class, String)} as  its first operation.
     65  * </p>
     66  * For more information on content provider testing, please see
     67  * <a href="{@docRoot}guide/topics/testing/provider_testing.html">Content Provider Testing</a>.
     68  */
     69 public abstract class ProviderTestCase2<T extends ContentProvider> extends AndroidTestCase {
     70 
     71     Class<T> mProviderClass;
     72     String mProviderAuthority;
     73 
     74     private IsolatedContext mProviderContext;
     75     private MockContentResolver mResolver;
     76 
     77     private class MockContext2 extends MockContext {
     78 
     79         @Override
     80         public Resources getResources() {
     81             return getContext().getResources();
     82         }
     83 
     84         @Override
     85         public File getDir(String name, int mode) {
     86             // name the directory so the directory will be separated from
     87             // one created through the regular Context
     88             return getContext().getDir("mockcontext2_" + name, mode);
     89         }
     90 
     91         @Override
     92         public Context getApplicationContext() {
     93             return this;
     94         }
     95     }
     96     /**
     97      * Constructor.
     98      *
     99      * @param providerClass The class name of the provider under test
    100      * @param providerAuthority The provider's authority string
    101      */
    102     public ProviderTestCase2(Class<T> providerClass, String providerAuthority) {
    103         mProviderClass = providerClass;
    104         mProviderAuthority = providerAuthority;
    105     }
    106 
    107     private T mProvider;
    108 
    109     /**
    110      * Returns the content provider created by this class in the {@link #setUp()} method.
    111      * @return T An instance of the provider class given as a parameter to the test case class.
    112      */
    113     public T getProvider() {
    114         return mProvider;
    115     }
    116 
    117     /**
    118      * Sets up the environment for the test fixture.
    119      * <p>
    120      * Creates a new
    121      * {@link android.test.mock.MockContentResolver}, a new IsolatedContext
    122      * that isolates the provider's file operations, and a new instance of
    123      * the provider under test within the isolated environment.
    124      * </p>
    125      *
    126      * @throws Exception
    127      */
    128     @Override
    129     protected void setUp() throws Exception {
    130         super.setUp();
    131 
    132         mResolver = new MockContentResolver();
    133         final String filenamePrefix = "test.";
    134         RenamingDelegatingContext targetContextWrapper = new
    135                 RenamingDelegatingContext(
    136                 new MockContext2(), // The context that most methods are
    137                                     //delegated to
    138                 getContext(), // The context that file methods are delegated to
    139                 filenamePrefix);
    140         mProviderContext = new IsolatedContext(mResolver, targetContextWrapper);
    141 
    142         mProvider = mProviderClass.newInstance();
    143         mProvider.attachInfo(mProviderContext, null);
    144         assertNotNull(mProvider);
    145         mResolver.addProvider(mProviderAuthority, getProvider());
    146     }
    147 
    148     /**
    149      * Tears down the environment for the test fixture.
    150      * <p>
    151      * Calls {@link android.content.ContentProvider#shutdown()} on the
    152      * {@link android.content.ContentProvider} represented by mProvider.
    153      */
    154     @Override
    155     protected void tearDown() throws Exception {
    156         mProvider.shutdown();
    157         super.tearDown();
    158     }
    159 
    160     /**
    161      * Gets the {@link MockContentResolver} created by this class during initialization. You
    162      * must use the methods of this resolver to access the provider under test.
    163      *
    164      * @return A {@link MockContentResolver} instance.
    165      */
    166     public MockContentResolver getMockContentResolver() {
    167         return mResolver;
    168     }
    169 
    170     /**
    171      * Gets the {@link IsolatedContext} created by this class during initialization.
    172      * @return The {@link IsolatedContext} instance
    173      */
    174     public IsolatedContext getMockContext() {
    175         return mProviderContext;
    176     }
    177 
    178     /**
    179      * <p>
    180      *      Creates a new content provider of the same type as that passed to the test case class,
    181      *      with an authority name set to the authority parameter, and using an SQLite database as
    182      *      the underlying data source. The SQL statement parameter is used to create the database.
    183      *      This method also creates a new {@link MockContentResolver} and adds the provider to it.
    184      * </p>
    185      * <p>
    186      *      Both the new provider and the new resolver are put into an {@link IsolatedContext}
    187      *      that uses the targetContext parameter for file operations and a {@link MockContext}
    188      *      for everything else. The IsolatedContext prepends the filenamePrefix parameter to
    189      *      file, database, and directory names.
    190      * </p>
    191      * <p>
    192      *      This is a convenience method for creating a "mock" provider that can contain test data.
    193      * </p>
    194      *
    195      * @param targetContext The context to use as the basis of the IsolatedContext
    196      * @param filenamePrefix A string that is prepended to file, database, and directory names
    197      * @param providerClass The type of the provider being tested
    198      * @param authority The authority string to associated with the test provider
    199      * @param databaseName The name assigned to the database
    200      * @param databaseVersion The version assigned to the database
    201      * @param sql A string containing the SQL statements that are needed to create the desired
    202      * database and its tables. The format is the same as that generated by the
    203      * <a href="http://www.sqlite.org/sqlite.html">sqlite3</a> tool's <code>.dump</code> command.
    204      * @return ContentResolver A new {@link MockContentResolver} linked to the provider
    205      *
    206      * @throws IllegalAccessException
    207      * @throws InstantiationException
    208      */
    209     public static <T extends ContentProvider> ContentResolver newResolverWithContentProviderFromSql(
    210             Context targetContext, String filenamePrefix, Class<T> providerClass, String authority,
    211             String databaseName, int databaseVersion, String sql)
    212             throws IllegalAccessException, InstantiationException {
    213         MockContentResolver resolver = new MockContentResolver();
    214         RenamingDelegatingContext targetContextWrapper = new RenamingDelegatingContext(
    215                 new MockContext(), // The context that most methods are delegated to
    216                 targetContext, // The context that file methods are delegated to
    217                 filenamePrefix);
    218         Context context = new IsolatedContext(resolver, targetContextWrapper);
    219         DatabaseUtils.createDbFromSqlStatements(context, databaseName, databaseVersion, sql);
    220 
    221         T provider = providerClass.newInstance();
    222         provider.attachInfo(context, null);
    223         resolver.addProvider(authority, provider);
    224 
    225         return resolver;
    226     }
    227 }
    228