连续的Android Junit测试不会反映底层数据库中的实际数据

时间:2014-01-30 06:40:58

标签: android database unit-testing junit

其他信息:

为了澄清,被测试的应用程序使用ContentProvider来访问数据库。

修改

如果有人愿意并且能够帮我调试这个。完整项目可用here。在issue107-contentprovider分支BaseballCardListAddCardsTest

问题:

当我分别运行两个Android JUnit测试时,它们通过就好了。但是,当我一起运行它们时,第一个通过而第二个通过。问题似乎是第一次测试运行会向底层数据库添加一行。 tearDown()正确删除了数据库,但第二个测试仍然以ListView中显示的脏数据开始,尽管数据库不包含额外的行。 (我使用adb shell确认了这一点。)有没有人有任何想法如何解决这个问题?

可以找到正在测试的Activity类here

这是我的测试代码:

/**
 * Tests for the {@link BaseballCardList} activity when the database contains
 * data.
 */
public class BaseballCardListWithDataTest extends
        ActivityInstrumentationTestCase2<BaseballCardList> {

    /**
     * Create instrumented test cases for {@link BaseballCardList}.
     */
    public BaseballCardListWithDataTest() {
        super(BaseballCardList.class);
    }

    /**
     * Set up test fixture. This consists of an instance of the
     * {@link BaseballCardList} activity, its {@link ListView}, and a populated
     * database.
     *
     * @throws Exception
     *             If an error occurs while chaining to the super class.
     */
    @Override
    public void setUp() throws Exception {
        super.setUp();

        this.inst = this.getInstrumentation();

        // Create the database and populate table with test data
        InputStream cardInputStream = this.inst.getContext().getAssets()
                .open(BBCTTestUtil.CARD_DATA);
        BaseballCardCsvFileReader cardInput = new BaseballCardCsvFileReader(
                cardInputStream, true);
        this.allCards = cardInput.getAllBaseballCards();
        cardInput.close();

        this.dbUtil = new DatabaseUtil(this.inst.getTargetContext());
        this.dbUtil.populateTable(this.allCards);

        // Start Activity
        this.activity = this.getActivity();
        this.listView = (ListView) this.activity
                .findViewById(android.R.id.list);
        this.newCard = new BaseballCard("Code Guru Apps", 1993, 1, 50000, 1,
                "Code Guru", "Code Guru Devs", "Catcher");
    }

    /**
     * Tear down the test fixture by calling {@link Activity#finish()} and
     * deleting the database.
     *
     * @throws Exception
     *             If an error occurs while chaining to the super class.
     */
    @Override
    public void tearDown() throws Exception {
        this.dbUtil.deleteDatabase();

        super.tearDown();
    }

    /**
     * Check preconditions which must hold to guarantee the validity of all
     * other tests. Assert that the {@link Activity} to test and its
     * {@link ListView} are not <code>null</code>, that the {@link ListView}
     * contains the expected data, and that the database was created with the
     * correct table and populated with the correct data.
     */
    public void testPreConditions() {
        Assert.assertNotNull(this.activity);

        BBCTTestUtil.assertDatabaseCreated(this.inst.getTargetContext());
        Assert.assertTrue(this.dbUtil.containsAllBaseballCards(this.allCards));

        Assert.assertNotNull(this.listView);
        BBCTTestUtil.assertListViewContainsItems(this.inst, this.allCards,
                this.listView);
    }

    /**
     * Test that the {@link ListView} is updated when the user adds a new card
     * which matches the current filter.
     *
     * @throws Throwable
     *             If an error occurs while the portion of the test on the UI
     *             thread runs.
     */
    public void testAddCardMatchingCurrentFilter() throws Throwable {
        this.testYearFilter();

        Activity cardDetails = BBCTTestUtil.testMenuItem(this.inst,
                this.activity, R.id.add_menu, BaseballCardDetails.class);
        BBCTTestUtil.addCard(this, cardDetails, this.newCard);
        BBCTTestUtil.clickCardDetailsDone(this, cardDetails);

        this.expectedCards.add(this.newCard);
        BBCTTestUtil.assertListViewContainsItems(this.inst, this.expectedCards,
                this.listView);
    }

    /**
     * Test that the {@link ListView} is updated when the user adds a new card
     * after an active filter was cleared.
     *
     * @throws Throwable
     *             If an error occurs while the portion of the test on the UI
     *             thread runs.
     */
    public void testAddCardAfterClearFilter() throws Throwable {
        this.testClearFilter();
        Activity cardDetails = BBCTTestUtil.testMenuItem(this.inst,
                this.activity, R.id.add_menu, BaseballCardDetails.class);
        BBCTTestUtil.addCard(this, cardDetails, this.newCard);
        BBCTTestUtil.clickCardDetailsDone(this, cardDetails);

        this.allCards.add(this.newCard);
        BBCTTestUtil.assertListViewContainsItems(this.inst, this.allCards,
                this.listView);
    }

    private List<BaseballCard> allCards;
    private List<BaseballCard> expectedCards;
    private Instrumentation inst = null;
    private Activity activity = null;
    private DatabaseUtil dbUtil = null;
    private ListView listView = null;
    private BaseballCard newCard = null;
    private static final int TIME_OUT = 5 * 1000; // 5 seconds
    private static final String TAG = BaseballCardListWithDataTest.class
            .getName();
}

1 个答案:

答案 0 :(得分:0)

似乎ContentProvider的生命周期与Application生命周期的生命周期相关联,而不是Activity的生命周期。另外,据我所知,ActivityInstrumentationTestCase2为所有测试创建了一个Application;只有Activity被销毁并重新开始每次测试。这意味着每个测试将共享相同的ContentProvider。这意味着数据库文件在ContentProvider的第一次访问时打开,并且仅在ActivityInstrumentationTestCase2中的所有测试方法完成后才关闭。由于数据库文件在测试用例之间保持打开,因此即使从基础文件系统中删除文件,也可以访问数据。我的解决方案是单独删除数据库的行而不是删除整个数据库。