2010-06-22 8 views
29

मैंने कुछ कक्षाओं (पैटर्न डीएओ के साथ) के भीतर android.database पैकेज से SQLiteOpenHelper का उपयोग कर डेटाबेस में पहुंच लागू की है।Android पर परीक्षण डेटाबेस: ProviderTestCase2 या RenamingDelegatingContext?

मैंने AndroidTestCase का उपयोग करके इन कक्षाओं के लिए कुछ जूनिट परीक्षण लिखे हैं लेकिन इससे परीक्षण के समान डेटाबेस का उपयोग करने का कारण बनता है।

मैंने पढ़ा है कि ProviderTestCase2 या RenamingDelegatingContext डेटाबेस का अलग-अलग परीक्षण करने के लिए उपयोग किया जा सकता है। अनजाने में मुझे कोई अच्छा ट्यूटोरियल/उदाहरण नहीं मिला जो दिखाता है कि ProviderTestCase2/RenamingDelegatingContext के साथ डेटाबेस का परीक्षण कैसे करें।

क्या कोई मुझे कहीं इंगित कर सकता है या मुझे कुछ टिप दे सकता है या डेटाबेस परीक्षण के लिए कुछ कोड साझा कर सकता है ?!

Cheeerrrrsss !! जियोर्जियो

+0

[जुनीट 4 शैली में परीक्षण एंड्रॉइड डेटाबेस] (http://www.singhajit.com/testing-android-database/) –

उत्तर

21

ProviderTestCase और RenamingDelegatingContext दोनों डेटाबेस को नष्ट कर देंगे यदि कोई पहले से ही इसके संदर्भ में इसे खोलने से पहले मौजूद है, तो इस अर्थ में वे दोनों SQLite डेटाबेस खोलने की दिशा में एक ही निम्न-स्तरीय दृष्टिकोण रखते हैं।

आप setUp() में अपने स्थिरता में डेटाबेस खोलकर इसका लाभ उठाते हैं, जिससे यह सुनिश्चित होगा कि आप प्रत्येक परीक्षण मामले से पहले एक नए डेटाबेस के साथ काम कर रहे हों।

मैं सुझाव दूंगा कि आप डेटाबेस एडाप्टर बनाने के बजाय सामग्री प्रदाताओं को लिखने के लिए जाएं। आप डेटा तक पहुंचने के लिए एक सामान्य इंटरफ़ेस का उपयोग कर सकते हैं, इसे डीबी में या नेटवर्क पर कहीं भी संग्रहीत किया जा सकता है, सामग्री प्रदाताओं के डिज़ाइन को आईपीसी ओवरहेड की लागत पर ऐसे डेटा तक पहुंचने के लिए समायोजित किया जा सकता है जिसमें से अधिकांश को ' टी के बारे में परवाह है।

यदि आपने SQLite डेटाबेस तक पहुंचने के लिए ऐसा किया है, तो फ्रेमवर्क एक अलग प्रक्रिया में आपके लिए डेटाबेस कनेक्शन को पूरी तरह से प्रबंधित करेगा। जोड़ा गया गोमांस के रूप में, ProviderTestCase2<ContentProvider> कोड के एक पंक्ति को लिखने के बिना आपके सामग्री प्रदाता के लिए पूरी तरह से बूट संदर्भ को बूटस्ट्रैप्स करता है।

लेकिन, ऐसा नहीं कहा जाता है कि बूटस्ट्रैपिंग करने के लिए यह इतना बड़ा प्रयास नहीं है। तो मान लीजिए कि आपके पास डेटाबेस एडाप्टर था;

public class MyAdapter { 

    private static final String DATABASE_NAME = "my.db"; 
    private static final String DATABASE_TABLE = "table"; 
    private static final int DATABASE_VERSION = 1; 


    /** 
    * Database queries 
    */ 
    private static final String DATABASE_CREATE_STATEMENT = "some awesome create statement"; 

    private final Context mCtx; 
    private SQLiteDatabase mDb; 
    private DatabaseHelper mDbHelper; 

    private static class DatabaseHelper extends SQLiteOpenHelper { 

     public DatabaseHelper(Context context) { 
      super(context, DATABASE_NAME, null, DATABASE_VERSION); 
     } 

     @Override 
     public void onCreate(SQLiteDatabase db) { 
      db.execSQL(DATABASE_CREATE_STATEMENT); 
     } 

     @Override 
     public void onUpgrade(SQLiteDatabase db, int a, int b) { 
      // here to enable this code to compile 
     } 
    } 

    /** 
    * Constructor - takes the provided context to allow for the database to be 
    * opened/created. 
    * 
    * @param context the Context within which to work. 
    */ 
    public MyAdapter(Context context) { 
     mCtx = context; 
    } 

    /** 
     * Open the last.fm database. If it cannot be opened, try to create a new 
     * instance of the database. If it cannot be created, throw an exception to 
     * signal the failure. 
     * 
     * @return this (self reference, allowing this to be chained in an 
     *   initialization call) 
     * @throws SQLException if the database could be neither opened or created 
     */ 
    public MyAdapter open() throws SQLException { 
     mDbHelper = new DatabaseHelper(mCtx); 
     mDb = mDbHelper.getWritableDatabase(); 
     return this; 
    } 

    public void close() { 
      mDbHelper.close(); 
     } 

} 

तो फिर तुम इस तरह के रूप में अपने परीक्षण लिख सकते हैं:: हम सिर्फ हमारे डेटाबेस में लेखन पहुँच रही फैंसी कुछ नहीं के लिए open() पर ध्यान केंद्रित करेंगे

public final class MyAdapterTests extends AndroidTestCase { 

    private static final String TEST_FILE_PREFIX = "test_"; 
private MyAdapter mMyAdapter; 

@Override 
protected void setUp() throws Exception { 
    super.setUp(); 

    RenamingDelegatingContext context 
     = new RenamingDelegatingContext(getContext(), TEST_FILE_PREFIX); 

    mMyAdapter = new MyAdapter(context); 
    mMyAdapter.open(); 
} 

@Override 
protected void tearDown() throws Exception { 
    super.tearDown(); 

    mMyAdapter.close(); 
    mMyAdapter = null; 
} 

public void testPreConditions() { 
    assertNotNull(mMyAdapter); 
} 

} 

तो क्या यहाँ क्या हो रहा है यह है कि संदर्भ कार्यान्वयन RenamingDelegatingContext, एक बार MyAdapter(context).open() कहा जाता है, हमेशा डेटाबेस को फिर से बना देगा। आपके द्वारा लिखे गए प्रत्येक परीक्षण को MyAdapter.DATABASE_CREATE_STATEMENT के बाद डेटाबेस की स्थिति के विरुद्ध जा रहा है।

+0

मैं शुरुआत से ContentProvider मार्ग नहीं जाने के लिए खुद को लात मार रहा था, लेकिन मैं आगे बढ़ गया और बनाया एक। अब परीक्षण सामग्री पर वापस ... – LostNomad311

+0

इसका मतलब क्या है 'RenamingDelegatingContext'? हम इसका इस्तेमाल क्यों कर रहे हैं? यह प्रत्येक विधि के लिए नया डेटाबेस बनाएगा? –

+0

मुझे लगता है कि 'AndroidTestCase'/'RenamingDelegatingContext' को' ActivityInstrumentationTestCase2' के साथ एक साथ चलाते समय डेटाबेस परीक्षण से परीक्षण तक रहता है। केवल 'एंड्रॉइडटेस्टकेस' चलाना हर बार डीबी को दोबारा शुरू करता है। – Tad

-1

सम्भावित समाधान इस विधि

myDataBase = SQLiteDatabase.openDatabase(DATABASE_NAME, null, SQLiteDatabase.OPEN_READWRITE); 

का उपयोग कर डेटाबेस को खोलने और अपने परीक्षण में डेटाबेस नाम बदलने के लिए हो सकता है। Here आप इस विधि के बारे में कुछ जानकारी पा सकते हैं।

1

मेरे पास एक ऐसा एप्लिकेशन है जो एप्लिकेशन को डेटा प्रदान करने के लिए एक SQLite डेटाबेस द्वारा समर्थित ContentProvider का उपयोग करता है।

PodcastDataProvider एप्लिकेशन द्वारा उपयोग किए जाने वाले वास्तविक डेटाप्रोवाइडर होने दें।

public abstract class AbstractPodcastDataProvider extends ProviderTestCase2<PodcastDataProvider>{ 
    public AbstractPodcastDataProvider(){ 
     this(PodcastDataProvider.class, Feed.BASE_AUTH); 
    } 

    public AbstractPodcastDataProvider(Class<PodcastDataProvider> providerClass, 
      String providerAuthority) { 
     super(providerClass, providerAuthority); 
    } 

    public void setUp() throws Exception{ 
     super.setUp(); 

     //clear out all the old data. 
     PodcastDataProvider dataProvider = 
      (PodcastDataProvider)getMockContentResolver() 
      .acquireContentProviderClient(Feed.BASE_AUTH) 
      .getLocalContentProvider(); 
     dataProvider.deleteAll(); 
    } 
} 
सेटअप करने के लिए

कि वास्तविक आवेदन तुलना में एक अलग डेटाबेस का समर्थन प्राप्त हो जाएगा एक परीक्षण डेटा प्रदाता:

तो आप निम्नलिखित की तरह कुछ के साथ एक परीक्षण प्रदाता सेट कर सकते हैं।

डीएओ का परीक्षण, एक और वर्ग जो AbstractPodcastDataProvider फैली बना सकते हैं और

getMockContentResolver(); 

विधि का उपयोग एक सामग्री समाधानकर्ता कि आवेदन डेटाबेस के बजाय परीक्षण डेटाबेस का उपयोग करेगा का एक उदाहरण प्राप्त करने के लिए करने के लिए।

0
private static String db_path = "/data/data/android.testdb/mydb"; 
private SQLiteDatabase sqliteDatabase = null; 
private Cursor cursor = null; 
private String[] fields; 

/* 
* (non-Javadoc) 
* 
* @see dinota.data.sqlite.IDataContext#getSQLiteDatabase() 
*/ 
public SQLiteDatabase getSQLiteDatabase() { 
    try { 

     sqliteDatabase = SQLiteDatabase.openDatabase(db_path, null, 
       SQLiteDatabase.OPEN_READWRITE); 
     sqliteDatabase.setVersion(1); 
     sqliteDatabase.setLocale(Locale.getDefault()); 
     sqliteDatabase.setLockingEnabled(true); 
     return sqliteDatabase; 
    } catch (Exception e) { 
     return null; 
    } 

} 

आप SQLite db का सटीक स्थान उपरोक्त विधि का उपयोग कर आप को खोजने आउट कर सकते हैं कि क्या यह एक sqlitedatabase देता है या नहीं देना है, तो (मेरे मामले में यह db_path है),।

6

मैं वास्तव में SQLiteOpenHelper के साथ डेटाबेस का उपयोग करता हूं और मेरे पास परीक्षण के लिए एक चाल है। विचार ऐप के सामान्य उपयोग और परीक्षण के दौरान इन-मेमोरी डीबी के दौरान मानक ऑन-फाइल संग्रहीत डीबी का उपयोग करना है। इस तरह आप अपने मानक डीबी में डेटा डालने/हटाने/अपडेट किए बिना प्रत्येक परीक्षण के लिए एक स्पष्ट डीबी का उपयोग कर सकते हैं। यह मेरे लिए ठीक काम करता है।

ध्यान रखें कि आप इन-मेमोरी डेटाबेस का उपयोग कर सकते हैं, बस डेटाबेस फ़ाइल के नाम के रूप में शून्य को पास कर सकते हैं। यह स्पष्ट रूप से एपीआई दस्तावेज में दस्तावेज है।

परीक्षण के दौरान इन-स्मृति डीबी का उपयोग कर के लाभ यहां समझाया गया है: https://attakornw.wordpress.com/2012/02/25/using-in-memory-sqlite-database-in-android-tests/

अपने प्रोजेक्ट में मैं DBHelper वर्ग जो फैली SQLiteHelper है। जैसा कि आप देख सकते हैं, मानक तरीके हैं। मैंने बस दो पैरामीटर के साथ एक कन्स्ट्रक्टर जोड़ा। अंतर यह है कि जब मैं सुपर कन्स्ट्रक्टर को कॉल करता हूं, तो मैं डीबी नाम के रूप में शून्य हो जाता हूं।

public class DBHelper extends SQLiteOpenHelper { 

    public static final int DATABASE_VERSION = 1; 
    public static final String DATABASE_NAME = "mydatabase.db"; 

    public DBHelper(Context context) { 
     super(context, DATABASE_NAME, null, DATABASE_VERSION); 
    } 

    public DBHelper(Context context, boolean testMode) { 
     super(context, null, null, DATABASE_VERSION); 
    } 

    public void onCreate(SQLiteDatabase db) { 
     //create statements 
    } 

    public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     //on upgrade policy 
    } 

    public void onDowngrade(SQLiteDatabase db, int oldVersion, int newVersion) { 
     //on downgrade policy 
    } 
} 

परियोजना में प्रत्येक "मॉडल" डीबीमोडेल को एक सार वर्ग प्रदान करता है।

public abstract class DBModel { 
    protected DBHelper dbhelper; 

    public DBModel(Context context) { 
     dbhelper = new DBHelper(context); 
    } 

    //other declarations and utility function omitted 

} 

के रूप में यहाँ पर चर्चा की: How can I find out if code is running inside a JUnit test or not? अगर आप JUnit परीक्षण चल रहे हैं, बस स्टैक ट्रेस तत्वों में खोज की स्थापना के लिए एक तरह से होती है। एक conseguence रूप में, मैं DBModel निर्माता संशोधित

public abstract class DBModel { 
    protected DBHelper dbhelper; 

    public DBModel(Context context) { 
     if(isJUnitTest()) { 
      dbhelper = new DBHelper(context, true); 
     } else { 
      dbhelper = new DBHelper(context); 
     } 
    } 

    private boolean isJUnitTest() { 
     StackTraceElement[] stackTrace = Thread.currentThread().getStackTrace(); 
     List<StackTraceElement> list = Arrays.asList(stackTrace); 
     for (StackTraceElement element : list) { 
      if (element.getClassName().startsWith("junit.")) { 
       return true; 
      } 
     } 
     return false; 
    } 

    //other declarations and utility function omitted 

} 

ध्यान दें कि

startsWith("junit.") 

हो सकता है

startsWith("org.junit.") 
अपने मामले में

+0

कुछ उत्कृष्ट विचारों और सुझावों के लिए धन्यवाद। – JulianHarty

संबंधित मुद्दे