Последовательные тесты Android Junit не отражают реальные данные в базовой базе данных

Дополнительная информация:

Чтобы уточнить, в тестируемом приложении используется ContentProvider для доступа к базе данных.

Edit:

Если кто-то хочет и может помочь мне отладить это. Полный проект доступен здесь. В ветке issue107-contentprovider BaseballCardListAddCardsTest.

Вопрос:

Когда я запускаю два моих теста Android JUnit отдельно, они проходят отлично. Однако, когда я запускаю их вместе, первый проходит, а второй терпит неудачу. Проблема заключается в том, что первый тестовый прогон добавляет строку в базовую базу данных. tearDown() корректно удаляет базу данных, но второй тест по-прежнему начинается с грязных данных, отображаемых в ListView, хотя база данных не содержит дополнительную строку. (Я подтвердил это с помощью adb shell.) Есть ли у кого-нибудь идеи, как я могу исправить эту проблему?

Проверяемый класс действия можно найти здесь.

Вот мой тестовый код:

/**
 * 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

Похоже, что жизненный цикл ContentProvider привязан к объекту Application not of Activity, который его поддерживает. Кроме того, из того, что я могу сказать, ActivityInstrumentationTestCase2 создает один Application для всех тестов; только Activity уничтожается и перезапускается для каждого теста. Это означает, что каждый тест будет иметь один и тот же ContentProvider. Это означает, что файл базы данных открывается с первым доступом ContentProvider и закрывается только после завершения всех методов тестирования в ActivityInstrumentationTestCase2. Поскольку файл базы данных остается открытым между тестовыми примерами, доступ к данным можно получить даже после удаления файла из базовой файловой системы. Мое решение состояло в том, чтобы удалить строки базы данных индивидуально, а не удалять всю базу данных.