javaandroiddatabaserx-javaandroid-room

"java.lang.AssertionError: Value not present" while testing Database implemented using Room & RxJava


I am very fresh to RxJava library, Reactive programming & Room Database. So I just learned recently that you have to test your Data Layer before working on it. So I am writing all these codes in java.

My Database class

@Database(entities = {SimpleTask.class},version = 1,exportSchema = false)
@TypeConverters({CalendarConverter.class})
public abstract class TaskDatabase extends RoomDatabase {

    public abstract SimpleTaskDao simpleTaskDao();

}

My SimpleTaskDao

@Dao
public interface SimpleTaskDao {

    @Query("SELECT * FROM simpleTask")
    public Observable<List<SimpleTask>> observeAll();

    @Upsert
    public Completable upsert(SimpleTask task);

    @Upsert
    public Completable upsertAll(List<SimpleTask> taskList);

    @Query("UPDATE simpleTask SET `check`=:check WHERE `id`=:id")
    public Completable updateCompleted(int id, boolean check);

    @Query("DELETE FROM simpleTask")
    public Completable deleteAll();

}

My Database Module

@Module
@InstallIn(SingletonComponent.class)
public class DatabaseModule{
    final String DATABASE_NAME = "not_disclosing_this_here";

    @Singleton
    @Provides
    TaskDatabase provideDatabase(@ApplicationContext Context context){
        return Room.databaseBuilder(context.getApplicationContext(),TaskDatabase.class,DATABASE_NAME).build();
    }

    @Provides
    SimpleTaskDao provideSimpleTaskDao(TaskDatabase database) {
        return database.simpleTaskDao();
    }
}

My SimpleTask Model

@Entity(
        tableName = "simpleTask"
)
final public class SimpleTask {
    @PrimaryKey(autoGenerate = true)
    private int id;
    @ColumnInfo(name = "title")
    private String title;
    @ColumnInfo(name = "details")
    private String details;
    @ColumnInfo(name = "alarm")
    @TypeConverters(CalendarConverter.class)
    private Calendar alarm;
    @ColumnInfo(name = "repeat")
    private int repeat;
    @ColumnInfo(name = "check")
    private boolean check;

    @Ignore
    public SimpleTask(){}
    @Ignore
    public SimpleTask(String input){
        setTitle(input);
        setDetails("");
        setAlarm(null);
        setRepeat(0);
        setCheck(false);
    }
    @Ignore
    public SimpleTask(String title, String details, Calendar alarm, int repeat, boolean check){
        setTitle(title);
        setDetails(details);
        setAlarm(alarm);
        setRepeat(repeat);
        setCheck(check);
    }
    public SimpleTask(int id,String title, String details, Calendar alarm, int repeat, boolean check){
        setId(id);
        setTitle(title);
        setDetails(details);
        setAlarm(alarm);
        setRepeat(repeat);
        setCheck(check);
        Log.d("data creation","simple task created - "+id+title+alarm.toString()+repeat+check);
    }

    @Ignore
    public SimpleTask(String title, String desc) {
        setTitle(title);
        setDetails(desc);
    }

    @Ignore
    public SimpleTask(int id,String title, String desc) {
        setId(id);
        setTitle(title);
        setDetails(desc);
    }


    //    getter and setters

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public boolean isCheck() {
        return check;
    }

    public void setCheck(boolean check) {
        this.check = check;
    }

    public int getRepeat() {
        return repeat;
    }

    public void setRepeat(int repeat) {
        this.repeat = repeat;
    }

    public String getDetails() {
        return details;
    }

    public void setDetails(String details) {
        this.details = details;
    }

    public String getTitle() {
        return title;
    }

    public void setTitle(String title) {
        this.title = title;
    }

    public Calendar getAlarm() {
        return alarm;
    }

    public void setAlarm(Calendar alarm) {
        this.alarm = alarm;
    }

And now for the testing My SimpleTaskDaoTest

public class SimpleTaskDaoTest {
    private TaskDatabase database;

    @Before
    public void initDb(){
        database = Room.inMemoryDatabaseBuilder(
                getApplicationContext(),
                TaskDatabase.class
        ).allowMainThreadQueries().build();
    }

    @Test
    public void insertTaskAndGetTask(){

        SimpleTask task = new SimpleTask(34,"title","description", Calendar.getInstance(),1,false);

        database.simpleTaskDao().upsert(task);

        TestObserver<List<SimpleTask>> testObserver = new TestObserver<>();
        database.simpleTaskDao().observeAll()
                .firstElement()
                .toObservable()
                .subscribe(testObserver);

        testObserver.awaitTerminalEvent();
        testObserver.assertNoErrors();
        testObserver.assertValue(taskList -> taskList.size()==1);

    }
}

so after running the insertTaskAndGetTask() I get this error - java.lang.AssertionError: Value not present (latch = 0, values = 1, errors = 0, completions = 1)

Ofcourse I understand that the SimpleTask List being emitted by the observer is empty, but why?, I have tried researching this up but I am not able to figure it out!!!


Solution

  • You're not subscribing to the Completable returned by this call, which means the upsert never happens:

        database.simpleTaskDao().upsert(task);
    

    You need to chain this call to your subsequent call to observeAll(), to make sure they both happen, and they happen in the correct order:

     public void insertTaskAndGetTask(){
    
            SimpleTask task = new SimpleTask(34,"title","description", Calendar.getInstance(),1,false);
            TestObserver<List<SimpleTask>> testObserver = new TestObserver<>();
            database.simpleTaskDao().upsert(task)
                    .andThen(database.simpleTaskDao().observeAll())
                    .firstElement()
                    .toObservable()
                    .subscribe(testObserver);
    
            testObserver.awaitTerminalEvent();
            testObserver.assertNoErrors();
            testObserver.assertValue(taskList -> taskList.size()==1);
    
        }