jeudi 11 février 2021

How to best test each component in a Room database implementation?

I'll try to keep this simple and on point. I'm an Android developer noob. I did ask one question here thus far about SQLite DB files and it was helpful. Unfortunately, I still seem to be caught in a loop of stumbling -- and quite frankly, can't even recall the dozens upon dozens of modifications I've made while attempting to figure this out. Additionally, it's probably helpful for me to mention, I'm not a fan of debug systems. I've felt they're a bit convoluted and, so far, stuck to using console, log messages and breadcrumbs to see the progress of my programs.

Typically, I create a class or component, create a main program with very basic, essential elements to test, create another method or new class, add an example to main to test the new item, and so on. However, Room's abstraction layers and behind-the-scenes functions make that approach difficult. Also, there are Android aspects I don't yet have a grasp on, e.g. "context", increasing the difficulty of tracking problems/mistakes down.

So, how can I check my setup of each layer/stage, preferably only moving to the next when I know the previous is functioning properly?

I'm not so much asking to be spoon fed, but if you could comment on what I have thus far, I could learn by example.

@Database(entities = {Food.class, Ingredient.class, Recipe.class}, version = 3, exportSchema = false)
public abstract class AppDatabase extends RoomDatabase {
    public abstract IRecipeDAO recipeDao();
}

@Dao
public interface IRecipeDAO {
    @Query("SELECT name FROM recipe")
    List<String> testQuery();
}

public class RecipeRepository {
    private final String DB_FILENAME = "Recipe.db";
    private final String DB_ASSET_FILE = "database/RecipesData3.db";
    private AppDatabase recipeDatabase;

    // constructor with database initialization
    public RecipeRepository(Context context) {
        recipeDatabase = Room.databaseBuilder(context, AppDatabase.class, DB_FILENAME)
                .createFromAsset(DB_ASSET_FILE)
                .build();
    }

    // getter methods
    public List<String> doDBTest() {
        return recipeDatabase.recipeDao().testQuery();
    }
}

public class RecipeViewModel extends AndroidViewModel {
    private RecipeRepository recipeRepo;
    private List<String> testData;

    // constructor
    public RecipeViewModel(Application application) {
        super(application);
        recipeRepo = new RecipeRepository(application);
        testData = recipeRepo.doDBTest();
    }

    public List<String> testGetName() { return testData; }
}

public class MainActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // UI items
        TextView recipeNameText = findViewById(R.id.recipeNameText);

        RecipeViewModel recipeModel = new ViewModelProvider(this)
            .get(RecipeViewModel.class);
    }
}

Here are the last errors I've encountered during build/execution:

2021-02-08 10:42:18.977 30834-30834/com.example.purelyvegan E/AndroidRuntime: FATAL EXCEPTION: main Process: com.example.purelyvegan, PID: 30834 java.lang.RuntimeException: Unable to start activity ComponentInfo{com.example.purelyvegan/com.example.purelyvegan.MainActivity}: java.lang.RuntimeException: Cannot create an instance of class com.example.purelyvegan.RecipeViewModel at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3270) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409) at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83) at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135) at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95) at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016) at android.os.Handler.dispatchMessage(Handler.java:107) at android.os.Looper.loop(Looper.java:214) at android.app.ActivityThread.main(ActivityThread.java:7356) at java.lang.reflect.Method.invoke(Native Method) at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492) at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930) Caused by: java.lang.RuntimeException: Cannot create an instance of class com.example.purelyvegan.RecipeViewModel at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:275) at com.example.purelyvegan.MainActivity.onCreate(MainActivity.java:28) at android.app.Activity.performCreate(Activity.java:7802) at android.app.Activity.performCreate(Activity.java:7791) at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299) at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245) at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)  at android.os.Handler.dispatchMessage(Handler.java:107)  at android.os.Looper.loop(Looper.java:214)  at android.app.ActivityThread.main(ActivityThread.java:7356)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)  Caused by: java.lang.reflect.InvocationTargetException at java.lang.reflect.Constructor.newInstance0(Native Method) at java.lang.reflect.Constructor.newInstance(Constructor.java:343) at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267) at com.example.purelyvegan.MainActivity.onCreate(MainActivity.java:28)  at android.app.Activity.performCreate(Activity.java:7802)  at android.app.Activity.performCreate(Activity.java:7791)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)  at android.os.Handler.dispatchMessage(Handler.java:107)  at android.os.Looper.loop(Looper.java:214)  at android.app.ActivityThread.main(ActivityThread.java:7356)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)  Caused by: java.lang.RuntimeException: Unable to copy database file. at androidx.room.SQLiteCopyOpenHelper.verifyDatabaseFile(SQLiteCopyOpenHelper.java:131) at androidx.room.SQLiteCopyOpenHelper.getWritableDatabase(SQLiteCopyOpenHelper.java:87) at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476) at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281) at com.example.purelyvegan.IRecipeDAO_Impl.testQuery(IRecipeDAO_Impl.java:25) at com.example.purelyvegan.RecipeRepository.doDBTest(RecipeRepository.java:24) at com.example.purelyvegan.RecipeViewModel.(RecipeViewModel.java:18) at java.lang.reflect.Constructor.newInstance0(Native Method)  at java.lang.reflect.Constructor.newInstance(Constructor.java:343)  at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)  at com.example.purelyvegan.MainActivity.onCreate(MainActivity.java:28)  at android.app.Activity.performCreate(Activity.java:7802)  at android.app.Activity.performCreate(Activity.java:7791)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)  at android.os.Handler.dispatchMessage(Handler.java:107)  at android.os.Looper.loop(Looper.java:214)  at android.app.ActivityThread.main(ActivityThread.java:7356)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)  Caused by: java.io.FileNotFoundException: database/RecipesData.db at android.content.res.AssetManager.nativeOpenAsset(Native Method) at android.content.res.AssetManager.open(AssetManager.java:824) at android.content.res.AssetManager.open(AssetManager.java:801) at androidx.room.SQLiteCopyOpenHelper.copyDatabaseFile(SQLiteCopyOpenHelper.java:178) at androidx.room.SQLiteCopyOpenHelper.verifyDatabaseFile(SQLiteCopyOpenHelper.java:128) at androidx.room.SQLiteCopyOpenHelper.getWritableDatabase(SQLiteCopyOpenHelper.java:87)  at androidx.room.RoomDatabase.inTransaction(RoomDatabase.java:476)  at androidx.room.RoomDatabase.assertNotSuspendingTransaction(RoomDatabase.java:281)  at com.example.purelyvegan.IRecipeDAO_Impl.testQuery(IRecipeDAO_Impl.java:25)  at com.example.purelyvegan.RecipeRepository.doDBTest(RecipeRepository.java:24)  at com.example.purelyvegan.RecipeViewModel.(RecipeViewModel.java:18)  at java.lang.reflect.Constructor.newInstance0(Native Method)  at java.lang.reflect.Constructor.newInstance(Constructor.java:343)  at androidx.lifecycle.ViewModelProvider$AndroidViewModelFactory.create(ViewModelProvider.java:267)  at com.example.purelyvegan.MainActivity.onCreate(MainActivity.java:28)  at android.app.Activity.performCreate(Activity.java:7802)  at android.app.Activity.performCreate(Activity.java:7791)  at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1299)  at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3245)  at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3409)  at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:83)  at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:135)  at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:95)  at android.app.ActivityThread$H.handleMessage(ActivityThread.java:2016)  at android.os.Handler.dispatchMessage(Handler.java:107)  at android.os.Looper.loop(Looper.java:214)  at android.app.ActivityThread.main(ActivityThread.java:7356)  at java.lang.reflect.Method.invoke(Native Method)  at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:492)  at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:930)  2021-02-08 10:42:19.015 30834-30834/com.example.purelyvegan I/Process: Sending signal. PID: 30834 SIG: 9

Aucun commentaire:

Enregistrer un commentaire