繁体   English   中英

Android Room JUnit 测试:“AsyncTask #1” java.lang.IllegalStateException:无法执行此操作,因为当前没有事务

[英]Android Room JUnit testing: "AsyncTask #1" java.lang.IllegalStateException: Cannot perform this operation because there is no current transaction

我正在尝试对我的项目进行简单的测试,但是这个异常阻碍了我,我找不到原因。

我做了一个简单的测试,将一些新客户插入到我的数据库中。 我在插入客户时遇到的第一个问题是我无法在主线程中插入数据,所以我使用了AsyncTask.execute(new Runnable())但这次我遇到了这个问题。

我提供了以下课程,希望能提供很好的洞察力。

测试类:

@RunWith(RobolectricTestRunner.class)
public class ExampleUnitTest {
ShopDatabase db;
private CustomerDao customerDao;

@Before
public void createDB() {
    Context context = ApplicationProvider.getApplicationContext();
    db = Room.inMemoryDatabaseBuilder(context, ShopDatabase.class).build();
    customerDao = db.customerDao();
}

@Test
public void createUser(){
    final Customer customer = new Customer("Test", "Test test", Date.valueOf("2020-10-10"));

    AsyncTask.execute(new Runnable() {
        @Override
        public void run() {
            customerDao.insert(customer);
        }
    });

    Customer customerFound = customerDao.getCustomerByName("Test", "Test test");
    assertEquals(customerFound.getFirstName(), customer.getFirstName(), "Could not find user..");
}

@After
public void closeDB() {
    db.close();
}

存储库:

public class Repository {

private CustomerDao customerDao;

private LiveData<List<Customer>> allCustomers;

private Customer customer;

public Repository(Application application) {
    // Get DB instance
    ShopDatabase db = ShopDatabase.getInstance(application);

    customerDao = db.customerDao();

    allCustomers = customerDao.getAllCustomers();
}

public void insert(Customer customer) {
    new InsertCustomerAsyncTask(customerDao).execute(customer);
}

public Customer getCustomerByName(String first, String last) {
    return customerDao.getCustomerByName(first, last);
}

public LiveData<List<Customer>> getAllCustomers() {
    return allCustomers;
}

// Inner Async class to insert customers
private static class InsertCustomerAsyncTask extends AsyncTask<Customer, Void, Void> {
    private CustomerDao customerDao;

    public InsertCustomerAsyncTask(CustomerDao customerDao) {
        this.customerDao = customerDao;
    }

    @Override
    protected Void doInBackground(Customer... customers) {
        customerDao.insert(customers[0]);
        return null;
    }
}

数据库:

@Database(entities = {Customer.class}, version = 1)
@TypeConverters({Converters.class})
public abstract class ShopDatabase extends RoomDatabase {
private static ShopDatabase instance;

public abstract CustomerDao customerDao();

public static synchronized ShopDatabase getInstance(Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(context.getApplicationContext(), 
ShopDatabase.class,"shop_database")
                .fallbackToDestructiveMigration()
                .addCallback(roomCallback)
                .build();
    }
    return instance;
}

private static RoomDatabase.Callback roomCallback = new RoomDatabase.Callback() {
    @Override
    public void onCreate(@NonNull SupportSQLiteDatabase db) {
        super.onCreate(db);
        new PopulateDbAsyncTask(instance).execute();
    }
};

private static class PopulateDbAsyncTask extends AsyncTask<Void, Void, Void> {
    private CustomerDao customerDao;

    PopulateDbAsyncTask(ShopDatabase db) {
        customerDao = db.customerDao();
    }

    @Override
    protected Void doInBackground(Void... voids) {
       // Customers
        long c = customerDao.insert(new Customer("One", "A", Date.valueOf("2019-05-10")));
        long c2 = customerDao.insert(new Customer("Two", "B", Date.valueOf("2020-07-10")));
        long c3 = customerDao.insert(new Customer("Three", "C", Date.valueOf("1860-12-10")));

        return null;
    }
}
}

首先,我认为这是因为我的应用程序没有运行,所以这意味着我的数据库已关闭,但事实并非如此。 我在测试时打开了我的应用程序。

其次 - 当我在实例化我的数据库( db = Room.inMemoryDatabaseBuilder(context, ShopDatabase.class).build(); )后检查数据库是否打开时 - db.isOpen() -> 它每次都返回false

什么会导致问题?

当我在实例化我的数据库( db = Room.inMemoryDatabaseBuilder(context, ShopDatabase.class).build(); )后检查数据库是否打开时 - db.isOpen() -> 它每次都返回 false 。

在您尝试访问数据库之前,不会打开该数据库。 您可以在返回实例之前强制访问它(获取可写或可读的数据库/连接,也就是打开数据库文件本身,这一切都代表您在幕后完成)。 例如

......
instance.getOpenHelper().getWritableDatabase();
return instance;

例子

使用 :-

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

    shopDatabase = ShopDatabase.getInstance(this);
    boolean dbopen = shopDatabase.isOpen();
    if (dbopen); //<<<<<<<<<< breakpoint here

}

和 :-

public static synchronized ShopDatabase getInstance(Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(context.getApplicationContext(),
                ShopDatabase.class,"shop_database")
                .fallbackToDestructiveMigration()
                .addCallback(roomCallback)
                .build();
    }
    //instance.getOpenHelper().getWritableDatabase();
    return instance;
}

结果是

在此处输入图片说明

更改为使用:-

public static synchronized ShopDatabase getInstance(Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(context.getApplicationContext(),
                ShopDatabase.class,"shop_database")
                .fallbackToDestructiveMigration()
                .addCallback(roomCallback)
                .build();
    }
    instance.getOpenHelper().getWritableDatabase(); //<<<<<<<<< ADDED
    return instance;
}

结果是 :-

在此处输入图片说明

我无法在主线程中插入数据

如果在构建时添加.allowMainThreadQueries() ,则可以

例如

public static synchronized ShopDatabase getInstance(Context context) {
    if (instance == null) {
        instance = Room.databaseBuilder(context.getApplicationContext(),
                ShopDatabase.class,"shop_database")
                .fallbackToDestructiveMigration()
                .allowMainThreadQueries()
                .addCallback(roomCallback)
                .build();
    }
    instance.getOpenHelper().getWritableDatabase();
    return instance;
}
  • 不过,您可能不希望使用它。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM