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