I get error of this:
junit.framework.AssertionFailedError at
com.example.sirivan.myfirstapp.test.TestDb.testCreateDb(TestDb.java:22)
TestDb.java
public class TestDb extends AndroidTestCase {
public static final String LOG_TAG = TestDb.class.getSimpleName();
public void testCreateDb() throws Throwable{
assertTrue(mContext.deleteDatabase(WeatherDbHelper.DATABASE_NAME));
SQLiteDatabase db = new WeatherDbHelper(
this.mContext).getWritableDatabase();
assertEquals(true, db.isOpen());
db.close();
}
}
Following the documentation:
http://developer.android.com/reference/android/content/Context.html#deleteDatabase(java.lang.String)
Returns true if the database was successfully deleted; else false.
Related
When I run only method testInsert() test completes with no problem, but when I run a whole class I've got an error:
java.lang.NoSuchMethodError: com.dataart.kvarivoda.myapplication.api.PlacesApi.getNearbyPlaces(Ljava/lang/String;Ljava/lang/String;I)Lretrofit2/Call;
at GetPlacesTest.testLogin(GetPlacesTest.java:61)
....
Retrofit #GET interface is:
public interface PlacesApi {
#GET("/maps/api/place/nearbysearch/json")
PlacesResults getNearbyPlaces(#Query("key") String key, #Query("location") String location, #Query("radius") int radius);
}
My test class is:
public class GetPlacesTest extends ProviderTestCase2 {
PlacesApi mockApi;
EventBus mockEventBus;
PlacesApi api;
Cursor cursor;
String webApiKey;
public GetPlacesTest() {
super(PlacesContentProvider.class, "com.example.myName.myapplication.database.PROVE");
}
public void setUp() throws Exception {
super.setUp();
setContext(InstrumentationRegistry.getTargetContext());
//MockitoAnnotations.initMocks(this);
mockApi = Mockito.mock(PlacesApi.class);
mockEventBus = Mockito.mock(EventBus.class);
webApiKey = getContext().getResources().getString(R.string.webApiKey);
api = ((PlacesApp) getApplication()).getApi();
}
#Override
protected void tearDown() throws Exception {
super.tearDown();
if (cursor != null) {
cursor.close();
}
}
#Test
public void testInsert() throws Exception {
PlacesResults results1 = loadResults("getplaces.json");
Mockito.when(mockApi.getNearbyPlaces(eq("testkey"), Matchers.anyString(), Matchers.anyInt())).thenReturn(results1);
GetPlacesAction action = new GetPlacesAction(getContext().getContentResolver(), mockEventBus, mockApi, "testkey");
action.downloadPlaces();
//check
cursor = getContext().getContentResolver().query(PlacesContentProvider.getUri(DB.PlaceTable.DB_TABLE), null, null, null, null);
assertEquals(2, cursor.getCount());
cursor.moveToPosition(0);
assertEquals("461d123aeb1c1648abdd5e535989d2bc518cf28e", getColumn(DB.PlaceTable.COLUMN_ID));
assertEquals("Astral Tower & Residences", getColumn(DB.PlaceTable.COLUMN_TITLE));
assertEquals(getImageUrl("CoQBcwAAAMUTbLLt7doNLiVSnpGryeIJLVdrDnMPcqs3uV84zfvDklrBr1uYxitVMEZWzTD40xkM923ak8HfRtoGiNdi32mqzP6sKB3lOYNbbOQeaHZ3bStClwhWO3507ryh4bODvEfXc-l42r7rFXFAg9GLSd7N2tqoOgLwzTLray0d1sixEhAZaZ2_ajvBieZvUuPA72d7GhQTtFtpqT8j7UBYSHvq9AuRsoRSig"), getColumn(DB.PlaceTable.COLUMN_IMAGE));
assertEquals(locationToString(-33.868111), getColumn(DB.PlaceTable.COLUMN_LOCATION_LAT));
assertEquals(locationToString(151.195219), getColumn(DB.PlaceTable.COLUMN_LOCATION_LNG));
}
private PlacesResults loadResults(String file) throws IOException {
InputStream is = InstrumentationRegistry.getContext().getAssets().open(file);
return new GsonBuilder().create().fromJson(new InputStreamReader(is), PlacesResults.class);
}
private String getImageUrl(String photoReference) {
return new GoogleImagesUtil("testkey").getImageUrl(photoReference);
}
private String locationToString(double location) {
return String.valueOf(LocationsUtil.locationToInteger(location));
}
private String getColumn(String column) {
return cursor.getString(cursor.getColumnIndex(column));
}
private int getColumnInt(String column) {
return cursor.getInt(cursor.getColumnIndex(column));
}
}
After some trying I couldn't even compile and started to get “No tests found” error. Later I've found that there was some run configuration on the class, although I didn't add anything. I deleted run configuration following this answer:
https://stackoverflow.com/a/38190125/2574228
All the errors gone after that.
I'm trying to implement some tests in my application. One thing that I want to test is writing a java object to my db, then retrieving it and asserting the the object that comes out of the db matches the object that went in.
Here's my MySQLiteHelper application code:
import android.content.ContentValues;
import android.content.Context;
import android.database.Cursor;
import android.database.sqlite.SQLiteDatabase;
import android.database.sqlite.SQLiteOpenHelper;
import java.util.concurrent.atomic.AtomicInteger;
class MySQLiteHelper extends SQLiteOpenHelper {
private static final String DATABASE_NAME = "unittesttester.db";
private static final int DATABASE_VERSION = 8;
private static final String LOG_TAG = MySQLiteHelper.class.getSimpleName();
private static final int WEATHER_STALENESS_PERIOD_MS = 60 * 5 * 1000; //5 minutes
private AtomicInteger mOpenCounter = new AtomicInteger();
private static MySQLiteHelper mInstance = null;
private SQLiteDatabase db;
private Context mContext;
public static MySQLiteHelper getInstance(Context context) {
if (mInstance == null) {
mInstance = new MySQLiteHelper(context.getApplicationContext());
}
return mInstance;
}
private MySQLiteHelper(Context context) {
super(context, DATABASE_NAME, null, DATABASE_VERSION);
mContext = context;
}
#Override
public void onCreate(SQLiteDatabase db) {
db.execSQL(WeatherTable.CREATE_TABLE_WEATHER);
}
#Override
public void onUpgrade(SQLiteDatabase db, int oldVersion, int newVersion) {
if (newVersion <= DATABASE_VERSION) {
onCreate(db);
}
}
private synchronized SQLiteDatabase openDatabase() {
final int i = mOpenCounter.incrementAndGet();
if (i == 1) {
db = getWritableDatabase();
}
return db;
}
private synchronized void closeDatabase() {
final int i = mOpenCounter.decrementAndGet();
if (i == 0) {
db.close();
}
}
private void truncateWeatherTable() {
db = openDatabase();
db.delete(WeatherTable.TABLE_WEATHER, null, null);
closeDatabase();
}
public void deleteAndInsertWeather(Weather weather) {
db = openDatabase();
db.beginTransaction();
try {
truncateWeatherTable();
insertWeather(weather);
db.setTransactionSuccessful();
} finally {
db.endTransaction();
closeDatabase();
}
}
private void insertWeather(Weather weather) {
db = openDatabase();
db.insert(WeatherTable.TABLE_WEATHER, null, makeWeatherCv(weather));
closeDatabase();
}
public Weather getWeather() {
db = openDatabase();
String sql = "SELECT * FROM " + WeatherTable.TABLE_WEATHER;
Cursor c = null;
Weather weather = null;
try {
c = db.rawQuery(sql, null);
if (c.moveToFirst()) {
weather = makeWeather(c);
//If sample too old return null
if (System.currentTimeMillis() - weather.getTimestamp() > WEATHER_STALENESS_PERIOD_MS) {
weather = null;
truncateWeatherTable();
}
}
} finally {
if (c != null) {
c.close();
}
closeDatabase();
}
return weather;
}
private Weather makeWeather(Cursor c) {
Weather weather = new Weather();
weather.setTimestamp(c.getLong(c.getColumnIndex(WeatherTable.COLUMN_TIMESTAMP)));
weather.setElevation(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_ELEVATION)));
weather.setTemperature(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_TEMPERATURE)));
weather.setDusk(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DUSK)));
weather.setNighttime(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_NIGHTTIME)));
weather.setGravity(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_GRAVITY)));
weather.setDaytime(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DAYTIME)));
weather.setHumidity(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_HUMIDITY)));
weather.setPressure(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_PRESSURE)));
weather.setOkta(c.getDouble(c.getColumnIndex(WeatherTable.COLUMN_OKTA)));
weather.setDawn(c.getInt(c.getColumnIndex(WeatherTable.COLUMN_DAWN)));
return weather;
}
private ContentValues makeWeatherCv(Weather weather) {
ContentValues contentValues = new ContentValues();
contentValues.put(WeatherTable.COLUMN_TIMESTAMP, weather.getTimestamp());
contentValues.put(WeatherTable.COLUMN_TEMPERATURE, weather.getElevation());
contentValues.put(WeatherTable.COLUMN_TEMPERATURE, weather.getTemperature());
contentValues.put(WeatherTable.COLUMN_DUSK, weather.getDusk());
contentValues.put(WeatherTable.COLUMN_NIGHTTIME, weather.getNighttime());
contentValues.put(WeatherTable.COLUMN_GRAVITY, weather.getGravity());
contentValues.put(WeatherTable.COLUMN_DAYTIME, weather.getDaytime());
contentValues.put(WeatherTable.COLUMN_HUMIDITY, weather.getHumidity());
contentValues.put(WeatherTable.COLUMN_PRESSURE, weather.getPressure());
contentValues.put(WeatherTable.COLUMN_OKTA, weather.getOkta());
contentValues.put(WeatherTable.COLUMN_DAWN, weather.getDawn());
return contentValues;
}
}
Here's my test class for the class above:
import android.test.AndroidTestCase;
import android.test.RenamingDelegatingContext;
import org.junit.Test;
import static org.mockito.Mockito.*;
public class MySQLiteHelperTest extends AndroidTestCase {
private MySQLiteHelper db;
private Weather mockedWeather = mock(Weather.class);
#Override
public void setUp() throws Exception {
super.setUp();
context = new MockContext();
setContext(context);
assertNotNull(context);
RenamingDelegatingContext renamingContext = new RenamingDelegatingContext(getContext(), "test_");
db = MySQLiteHelper.getInstance(renamingContext);
assertNotNull(db);
when(mockedWeather.getDawn()).thenReturn(0);
when(mockedWeather.getDaytime()).thenReturn(1);
when(mockedWeather.getDusk()).thenReturn(2);
when(mockedWeather.getElevation()).thenReturn(3.0);
when(mockedWeather.getGravity()).thenReturn(4.0);
when(mockedWeather.getHumidity()).thenReturn(5.0);
when(mockedWeather.getNighttime()).thenReturn(6);
when(mockedWeather.getOkta()).thenReturn(7.0);
when(mockedWeather.getPressure()).thenReturn(8.0);
when(mockedWeather.getTemperature()).thenReturn(9.0);
when(mockedWeather.getTimestamp()).thenReturn(10L);
}
#Override
public void tearDown() throws Exception {
super.tearDown();
}
public void testGetInstance() throws Exception {
}
public void testOnCreate() throws Exception {
}
public void testOnUpgrade() throws Exception {
}
#Test
public void testDeleteAndInsertWeather() throws Exception {
db.deleteAndInsertWeather(mockedWeather);
Weather actualWeather = db.getWeather();
assertEquals(mockedWeather.getDawn(), actualWeather.getDawn());
assertEquals(mockedWeather.getDaytime(), actualWeather.getDaytime());
assertEquals(mockedWeather.getDusk(), actualWeather.getDusk());
assertEquals(mockedWeather.getElevation(), actualWeather.getElevation());
assertEquals(mockedWeather.getGravity(), actualWeather.getGravity());
assertEquals(mockedWeather.getHumidity(), actualWeather.getHumidity());
assertEquals(mockedWeather.getNighttime(), actualWeather.getNighttime());
assertEquals(mockedWeather.getOkta(), actualWeather.getOkta());
assertEquals(mockedWeather.getPressure(), actualWeather.getPressure());
assertEquals(mockedWeather.getTemperature(), actualWeather.getTemperature());
assertEquals(mockedWeather.getTimestamp(), actualWeather.getTimestamp());
}
public void testDeleteWeather() throws Exception {
}
public void testInsertWeather() throws Exception {
}
public void testGetWeather() throws Exception {
}
public void testWeatherMakeCv() throws Exception {
}
}
When I run the test I am getting a NPE during my test. It seems to occur when the MySQLiteHelper class has its db = getWritableDatabase() line. getWriteableDatabase() is a public method from the base class.
I don't think I understand why this test results in an NPE. In my test I call the static method, MySQLiteHelper.getInstance(Context context) which should initialize the class. It is my assumption that calling getInstance will provide me with a fully initialized instance of MySQLiteHelper. Why does this not seem to be happening?
EDIT:
The problem I have now is that when getWritableDatabase() is called it returns null instead of an instance of SQLiteDatabase.
I ended completing my goals of unit testing my sqlite database. The problem seemed to be that I needed to use the build artifact called Android Instrumentation Test instead of the Unit Test build artifact.
I setup a test class in my app/src/androidTest/java directory. The test class extended InstrumentationTestCase.
When I setup my database I use the context provided by getInstrumentation().getTargetContext(). This was important because originally I tried to use getInstrumentation().getContext() and I found that that would always result in a SQLiteCantOpenDatabaseException.
So it seemed my problems occurred because:
1) I wasn't using the correct test artifact
2) I wasn't using the correct test base class
3) I wasn't getting the context correctly
AndroidTestCase#getContext() returns whatever Context you've set with setContext() and you haven't set anything, so a null is returned`.
Using a null context with SQLiteOpenHelper will NPE when the database is being opened e.g. with getWritableDatabase().
See Getting context in AndroidTestCase or InstrumentationTestCase in Android Studio's Unit Test feature for more details on how to set up a Contex in test cases.
I'm beginner in android and call alarm manager in main activity,into the alarm manager write this code:
public class AlarmReciever extends BroadcastReceiver {
private static Context myContext;
#Override
public void onReceive(Context context, Intent intent) {
new HttpAsyncTask().execute("http://myHOST.ir/oflineValue.aspx");
}
private class HttpAsyncTask extends AsyncTask<String, Void, String> {
#Override
protected String doInBackground(String... urls) {
try {
String DATABASE_NAME = "TEMPFOOD";
String TABLE_NAME = "tempData";
SQLiteDatabase db;
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,myContext.MODE_PRIVATE, null);
}catch(Exception e)
{
}
}
#Override
protected void onPostExecute(String result) {
}
}
}
but in this line:
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,myContext.MODE_PRIVATE, null);
i get this error:
why i get that error?
Answer is in your question - second argument should be SQLiteDatabase.CursorFactory
Try to put null as second argument.
Second Argument of openOrCreateDatabase() must be SQLiteDatabase.CursorFactory which is optional and it is required in order to instantiate any Cursor by default. Use the value null as second argument, if you don't want to instantiate.
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,myContext.MODE_PRIVATE, null);
If you want to instantiate, then try the below code:-
db=SQLiteDatabase.openOrCreateDatabase(DATABASE_NAME,new SQLiteDatabase.CursorFactory() {
#Override
public Cursor newCursor(SQLiteDatabase db, SQLiteCursorDriver masterQuery, String editTable, SQLiteQuery query) {
//Assign the values of masterQuery,query,editTable as per your requirements
return new SQLiteCursor(masterQuery,editTable,query);
}
}, null);
I'm trying to setup roboelectric and fest in my own project. However when I try to run ./gradlew clean test in the command line I get the following errors in the test report:
http://pastebin.com/5gaJgftf
My project does build the app without errors though. I only get this issue when I try to run tests, so it seems that Roboelectric is not aware is not aware of my native sqlcipher binaries and other binaries.
So I tried loading it with a shadow class for the runner that loads up the necessary binaries:
#Config(emulateSdk = 18, shadows={MyJniClass.class})
#RunWith(RobolectricTestRunner.class)
public class MainActivityBuildTest {
#Test
public void testSomething() throws Exception {
Activity activity = Robolectric.buildActivity(MainActivity.class).create().get();
assertTrue(activity != null);
}
}
Using my custom jniloader shadow class
#Implements(RobolectricTestRunner.class)
class MyJniClass {
static {
try {
System.loadLibrary("libdatabase_sqlcipher");
System.loadLibrary("libdatabase_android");
System.loadLibrary("libstlport_shared");
} catch (UnsatisfiedLinkError e) {
// only ignore exception in non-android env
if ("Dalvik".equals(System.getProperty("java.vm.name"))) throw e;
}
}
}
You have issues to use sql cipher with robolectric?
My workaround is to use two different implementation of the SQLiteOpenHelper. One use sqlcipher and the another one the default database implementation. This both are behind a factory class, which create the SQLiteDatabase based on a static boolean flag, so the unscure database handling will be eliminated from progard.
The next issue is that both have different SQLiteDatabase classes. So again build a wrapper around the SQLiteDatabase which will be created with the right SQLiteDatabase from the SQLiteOpenHelper Wrapper. Take the Cipher variant as your base. you can ignore methods which exist at default SQLiteDatabase but not at the cipher variant. This wrapper class take the same static boolean flag to choose which database should be used. if make a mistake and take the wrong database then it should throw a null pointer exception ;)
in your app code you should now use only the wrapper classes.
example for DatabaseHelper wrapper
public class MyDatabaseHelper {
public static final String DATABASE_NAME = "my.db";
public static final int DATABASE_VERSION = 1;
MyEncryptedDatabaseHelper encryptedDatabase;
MyUnsecureDatabaseHelper unsecureDatabase;
public MyDatabaseHelper(Context context) {
if (ReleaseControl.USE_UNSECURE_DATABASE) {
unsecureDatabase = new MyUnsecureDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
return;
}
encryptedDatabase = new MyEncryptedDatabaseHelper(context, DATABASE_NAME, null, DATABASE_VERSION);
}
public MySQLiteDatabase getWritableDatabase(String password) throws MySQLiteException {
if (ReleaseControl.USE_UNSECURE_DATABASE) {
try {
return new MySQLiteDatabase(unsecureDatabase.getWritableDatabase());
} catch (android.database.SQLException e) {
throw new MySQLiteException(e);
}
}
try {
return new MySQLiteDatabase(encryptedDatabase.getWritableDatabase(password));
} catch (net.sqlcipher.database.SQLiteException e) {
throw new MySQLiteException(e);
}
}
}
and short snippet from SQLiteDatabase wrapper
public class MySQLiteDatabase {
private net.sqlcipher.database.SQLiteDatabase encryptedDatabase;
private android.database.sqlite.SQLiteDatabase unsecureDatabase;
public MySQLiteDatabase(SQLiteDatabase database) {
encryptedDatabase = database;
}
public MySQLiteDatabase(android.database.sqlite.SQLiteDatabase database) {
unsecureDatabase = database;
}
public static void loadLibs(android.content.Context context) {
if (ReleaseControl.USE_UNSECURE_DATABASE) { return; }
SQLiteDatabase.loadLibs(context);
}
public static int releaseMemory() {
if (ReleaseControl.USE_UNSECURE_DATABASE) {
return android.database.sqlite.SQLiteDatabase.releaseMemory();
}
return net.sqlcipher.database.SQLiteDatabase.releaseMemory();
}
public static SQLiteDatabase openDatabase(String path, String password, MyCursorFactory factory, int flags) {
if(factory == null) factory = new NullCursorFactory();
if (ReleaseControl.USE_UNSECURE_DATABASE) {
return new MySQLiteDatabase(android.database.sqlite.SQLiteDatabase.openDatabase(path, factory.getUnsecure(), flags));
}
return new MySQLiteDatabase(net.sqlcipher.database.SQLiteDatabase.openDatabase(path, password, factory.getEncrypted(), flags));
}
In robolectric test i set the USE_UNSECURE_DATABASE per reflection true
I'm trying to change my DatabaseInterface implementation by opening it in MyApplication extends Application and basically never closing it (I did some research and a Google engineer recommends it, see the linked question Best place to close database connection). The modifications I have made are quite minor but now the system throws me the following error when opening the database:
E/SQLiteDatabase(15690): android.database.sqlite.SQLiteException: not an error (code 0): Could not open the database in read/write mode.
Here is relevant code
MyApplication.java
#Override
public void onCreate() {
super.onCreate();
try {
DatabaseInterface.open();
} catch (SQLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
DatabaseInterface.java
public class DatabaseInterface extends SQLiteOpenHelper {
private final static String DB_PATH = Constants.DB_PATH;
private final static String DB_NAME = Constants.DB_NAME;
private static SQLiteDatabase mDatabase;
private Context mContext;
private static DatabaseInterface mInstance;
private DatabaseInterface(Context context) {
super(context, DB_NAME, null, 1);
this.mContext = context;
}
public static DatabaseInterface getInstance(Context context) {
if (mInstance == null) {
mInstance = new DatabaseInterface(context);
}
return mInstance;
}
public static void open() throws SQLException, IOException {
//Open the database
String path = DB_PATH + DB_NAME;
mDatabase = SQLiteDatabase.openOrCreateDatabase(new File(path), null);
}
}
Ok this was caused by me forgetting to add
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
to my AndroidManifest.xml as my database reside on the phone's external storage.