I have an Android app with a database with version 1.
I added a data column in one table and idi a migration into a new release.
The problem I have is how to do unit tests for this. I needed to check if old data are correct inserted in the new structure and the new column is added and filled in the right way.
How would I best do this? Thanks in advance.
You can create a test case that builds an old version of your database and then run your migration. Here is a stripped down example.
public class DbHelperTest extends AndroidTestCase {
private SQLiteDatabase db;
#Override
public void setUp() throws Exception {
super.setUp();
mContext = new RenamingDelegatingContext(getContext(), "db_helper_test_");
SQLiteDatabase.CursorFactory cursorFactory = new SQLiteDatabase.CursorFactory() {
#Override
public Cursor newCursor(final SQLiteDatabase db, final SQLiteCursorDriver masterQuery, final String editTable,
final SQLiteQuery query) {
return new SQLiteCursor(db, masterQuery, editTable, query);
}
};
db = SQLiteDatabase.create(cursorFactory);
createV14Db(db);
}
#Override
public void tearDown() throws Exception {
super.tearDown();
db.close();
}
private void createV14Db(SQLiteDatabase db) {
// Create tables and indices
db.execSQL(...);
// Create some data
db.execSQL(...);
}
public void testDbUpgrade() {
DbHelper dbHelper = new DbHelper(mContext);
dbHelper.onUpgrade(db, 14, 100);
// Check that things have been upgraded correctly
}
}
You have to test 2 scenarios :
User installs new version directly.
User is on an older version and upgrades to new version.
Testing the 2nd scenario is generally tricky.
What I generally do to test scenario 2 is :
Un-install the app from mobile.
I switch to code version of release 1 - Note that I use GIT and hence it is very easy to switch to older versions.
Run the app on device using Android studio.
Create some test data.
Switch to release 2 of code.
Start debugging in Android studio. At this point have break points in your DB upgrade methods to ensure that DB upgrade is smooth.
Continue with the rest of the testing.
Related
I'm new to writing Xamarin Android by about 8 months.
I have an application up on the Google Play Store and when the application first installs, it creates the sqlite database from code.
I had to make a database table change, I added a few columns.
When the application does it's auto update, where/how do I tell it to drop the database and recreate it, or is it automatic? I'd expect not.
I'm not worried about the data, it will be re-downloaded.
I looked at Assets, creating a text file and reading a command from it, but I can't remove the asset, so that was a dead end.
Thanks for any help.
I like to use the built-in SQLiteOpenHelper class to maintain the Sqlite version numbers and providing the process for upgrading the database.
Using the builtin Android.Database.Sqlite.SQLiteOpenHelper you can easily use it to maintain your database version and if the version changes, delete the database and start fresh with a blank one (no tables/no data).
Remember: This is destructive "upgrade"...
public class SqliteOnVersionChangeCreateBlankDB : SQLiteOpenHelper
{
new const string DatabaseName = "myDBName";
const int DatabaseVersion = 1;
public SqliteOnVersionChangeCreateBlankDB(Context context) : base(context, DatabaseName, null, DatabaseVersion)
{
}
public override SQLiteDatabase ReadableDatabase
{
get
{
try
{
return base.ReadableDatabase;
}
catch
{
File.Delete(DatabaseName);
return base.WritableDatabase;
}
}
}
public override void OnCreate(SQLiteDatabase db)
{
Console.WriteLine($"{db}");
// You can create the DB tables/data here if needed...
// or use your favorite SQLite framework/library later...
}
public override void OnUpgrade(SQLiteDatabase db, int oldVersion, int newVersion)
{
Console.WriteLine($"{db}:{oldVersion}:{newVersion}");
if (oldVersion < newVersion)
{
// Normally this is where you would alter the existing schema to the new version
// but this is a destructive upgrade.
db.Close();
File.Delete(db.Path);
}
}
}
Usage:
Starting with a version of 1 in the SQLiteOpenHelper subclass:
const int DatabaseVersion = 1;
Execute this code:
var sqliteHelper = new SqliteOnVersionChangeCreateBlankDB(this);
var db = sqliteHelper.ReadableDatabase;
db.Close();
You now have a blank database that is assigned version 1. It is empty, no tables/data so use your favorite Sqlite ORM/framework/library to create the tables and populate it with data...
Unless the database version changes, executing this code each time your app starts will not delete the existing database:
var sqliteHelper = new SqliteOnVersionChangeCreateBlankDB(this);
var db = sqliteHelper.ReadableDatabase;
db.Close();
Later on, App is updated and you also need to change the database, so assign a new version number that is higher the last, 2 in this case, to the database.
const int DatabaseVersion = 2;
Execute the same code as before:
var sqliteHelper = new SqliteOnVersionChangeCreateBlankDB(this);
var db = sqliteHelper.ReadableDatabase;
db.Close();
You now have a blank database again, but it is assigned version 2. Again your favorite Sqlite ORM/framework/library to create the tables and populate it with data...
First you might want to confirm your intended behavior. I would track your .sqlite file to see what happens to it given your workflow.
For the most part when an application is being updated from Google Play Store, all of your application's data will stay put. (As it is only updating and not uninstalling -> installing again)
You can mimic this behavior by applying the following in your debug environment:
If you find yourself in a scenario where you need to update the database to associate it with a new application update, then you would need some mechanism to compare your database version and if it is older than the application's code expects, you would then apply a schema change and potentially seed the database with initial information.
I'm trying to implement version control into my database. I have following code:
if (File.Exists (dbPath)) {
database = new SQLiteConnection(dbPath);
dbVersion = GetDatabaseVersion();
if (dbVersion != DATABASE_VERSION) {
CreateDatabase(dbPath);
database = new SQLiteConnection(dbPath);
SetDatabaseVersion(DATABASE_VERSION);
}
} else {
CreateDatabase(dbPath);
database = new SQLiteConnection(dbPath);
SetDatabaseVersion(DATABASE_VERSION);
}
When I run the code for the first time File.Exists (dbPath) returns false as expected. When I then stop the app and build and deploy again, File.Exists (dbPath) returns true (as expected) and the versions get checked. But when I change an entry in the database (not the version) and I build and deploy again File.Exists (dbPath) returns false. So I guess the sqlite-file gets deleted when it's changed?
What I want to achieve is that when the sqlite-file is changed, but the version numbers are still the same, the database of the app isn't updated. Only when the versions don't match, it has to be updated.
(It works perfectly for iOS this way, by the way)
Can anyone help me?
Thanks in advance.
It's difficult, without access to your debugger, to answer what's going wrong. However, your way of creating and updating your database looks unusual and unnecessarily complicated. You should consider using SQLiteOpenHelper, which will allow you a structure like this:
public class MyDatabase extends SQLiteOpenHelper {
private static final int VERION = ...;
public MyDatabase(Context context) {
super(context, "mydatabasename", null, VERION);
}
public void onCreate(SQLiteDatabase db) {
db.execSQL("create table...");
...
}
public void onUpgrade(SQLiteDatabase db, int oldVersion, intNewVersion) {
db.execSQL("...") // whatever you have to change from one version to another
}
}
This works without losing any database files.
You should tick this box in Visual Studio / Tools / Options / Xamarin / Android settings
I have an app released on the android market which uses sqlite and displays data. I want to know if I am sending an update for the app by adding features, should I upload a new database? What happens when users already having my app, click on update? Will the database update on its own? If the users are downloading my app for the first time, they will certainly get the new db content...but what about the existing users?? I want to know if I have to explicitly update the database in the program
When you create your new version... If you change the version of the database... The onUpgrade function will run on all the existing users:
public static final int dbVersion = 2;
protected static class DatabaseHelper extends SQLiteOpenHelper {
public DatabaseHelper(Context context) {
super(context, dbName, null, dbVersion);
}
#Override
public void onCreate(SQLiteDatabase db) {
//create tables
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
//what do you want to do to existing users? maybe recreate?
}
}
Why not create the sqlite database through code? That way your updates can update the SQL on the database (alter columns, add rows) without affecting the users existing data.
If you are changing database's attributes then on updation it will create problem and if the database's attributes are same then it will not have any effect...
You may use android.database.sqlite.SQLiteOpenHelper class it supports versions and migration mechanism
I am using Ormlite for the first time and I am trying to setup my DatabaseHelper to insert rows after creating the database's tables. I am getting a getWritableDatabase called recursively error when I do.
Here is my onCreate:
public void onCreate(SQLiteDatabase sqliteDatabase, ConnectionSource connectionSource) {
try {
TableUtils.createTable(databaseType, connectionSource, User.class);
// Add test user
User test = new User("test", "12345");
getUserDao().create(test);
} catch (SQLException e) {
Log.e(DatabaseHelper.class.getName(), "Unable to create databases", e);
}
}
The problem here was that #karnage was using an older version of ORMLite that had a bug with using the DAOs in the onCreate -- the pattern that he is using. This was fixed in version 4.6 (10/2010) and downloading and running the latest version works for him.
Here is the bug report:
https://sourceforge.net/tracker/?func=detail&aid=3117883&group_id=297653&atid=1255989
Here's the change log file to track new features and versions of ORMLite:
http://ormlite.com/changelog.txt
Hi I am new to android and I have a problem in creating a database.
public class database extends ListActivity {
/** Called when the activity is first created. */
private final String MY_DATABASE_NAME = "myCoolUserDB.db";
private final String MY_DATABASE_TABLE = "t_Users";
Context c;
#Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ArrayList<String> results = new ArrayList<String>();
setContentView(R.layout.main);
SQLiteDatabase mydb=null;
try
{
mydb.openOrCreateDatabase(MY_DATABASE_NAME, null);
} catch(Exception e){}
}
}
When I run this code it throws a run time exception. Please help me.
If you are going to call a static method like openOrCreateDatabase, do it on the class (SQLiteDatabase.openOrCreateDatabase(...)), not an instance. It's a lot clearer - the way you've done it looks like you're calling an instance method, so looks like a sure NullPointerException, which of course is misleading.
As someone else has stated, the stack trace would be the most useful thing when asking for help with an exception.
(Almost) never catch an exception without at the very least logging it. Don't just do nothing with it. There are of course exceptions to every rule, but let's not go there for the moment. Anyway, if you don't at least log it, you're just throwing away information that would tell you what went wrong when everything goes to crap later.
You shouldn't be using that method directly, and should instead be extending SQLiteOpenHelper . See the android developers page on data storage to get started (I'd post a link but apparently I'm only allowed one link in my post ?!), and since you've probably had to download the SDK to get going, look in the samples that come with it for the Notepad sample application. That contains a NotePadProvider class, which is a good example of both a content provider and database access, which often go hand-in-hand on android. I'd suggest compiling that application and making some simple changes to it before you jump into making your own one.
For working with sqlite database you need to create class extended from SQLiteOpenHelper:
private class DBHelper extends SQLiteOpenHelper {
public DBHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(CREATE_TABLES);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
db.execSQL(UPGRADE_TABLES);
}
}
Then you can get access to db using DbHelper object:
DBHelper dbHelper = new DBHelper(Activity.this);
SQLiteDatabase db = dbHelper.getReadableDatabase();
I run into the same problem. It figures out that two bugs happens during development
dir "databases" was not existent
accendently ".db" was created as directory.
They following code cover both
File dbFile = getDatabasePath ("abc.db");
if (dbFile.isDirectory ()) {
dbFile.delete();
}
if (! dbFile.exists()) {
String path = dbFile.getParent ();
new File (path).mkdirs ();
}
database = SQLiteDatabase.openDatabase (dbFile.getAbsolutePath (), this, SQLiteDatabase.OPEN_READWRITE | SQLiteDatabase.CREATE_IF_NECESSARY);
Hope this helps
I think SQLiteOpenHelper is only useful for "single table" databases. For multiple table applications I consider directly using SQLiteDatabase fit better to a good architecture.
This is a simple post which tells you how to insert data in to a SQLite database in Android and further more this links shows you how to retrieve data from a SQLite database in Android .