Имитация базы данных SQLite при тестировании Activity с помощью Robolectric

В последние несколько дней я начал играть с roboguice, robolectric и mockito. У меня есть небольшое Android-приложение с экраном входа в систему, содержащим AutoCompleteTextView для более быстрого ввода имени пользователя. Имена пользователей для AutoCompleteTextView хранятся в базе данных sqlite.

public class MainActivity extends RoboActivity implements View.OnClickListener {
@InjectView(R.id.startScreen_Login_Button) private Button loginButton;
@InjectView(R.id.startScreen_Cancel_Button) private Button cancelButton;
@InjectView(R.id.startScreen_forgotPwd_TextView) private TextView forgotPWTextView;
@InjectView(R.id.startScreen_Username_AutoCompleteTextView) private AutoCompleteTextView loginUsernameAutoCompleteTextView;
@InjectView(R.id.startScreen_Password_EditText) private EditText loginPasswordEditText;
@Inject private SharedPreferences sharedPreferences;
@Inject SQLiteDBAdapter dbAdapter;

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

    loginButton.setOnClickListener(this);
    cancelButton.setOnClickListener(this);
    forgotPWTextView.setOnClickListener(this);

    // Creating List for startScreen_Username_AutoCompleteTextView
    List<User> userList = dbAdapter.getUserList();
    ListIterator<User> it = userList.listIterator();
    List<String> userStringList = new ArrayList<String>();
    User user;
    while (it.hasNext()) {
        user = it.next();
        userStringList.add(user.getName());
    }

    loginUsernameAutoCompleteTextView.setAdapter(new ArrayAdapter<String>(this, R.layout.select_page_row, userStringList));
    }
...
}

Я хочу протестировать MainActivity с помощью robolectric, пытаясь издеваться над базой данных с помощью mockito. Это мой тестовый класс:

@RunWith(CustomRobolectricTestRunner.class)
public class MainActivityTest {

@Mock
SQLiteDBAdapter dbAdapter;

@Before
public void setUp() throws Exception {
    MockitoAnnotations.initMocks(this);
}

@Test
public void shouldHaveApplicationName() throws Exception {
    String appName = new MainActivity().getResources().getString(R.string.app_name);
    assertThat(appName, equalTo("OperationReport"));
}

@Test
public void testButtonsVisible()
{
    MainActivity mainActivity = new MainActivity();
    mainActivity.onCreate(null);
}
}

Вызов mainActivity.onCreate(null); запускает каскад ошибок, заканчивающийся строкой Cursor cursor = db.rawQuery(SQL_QUERY, null); моего метода getUserList в моем SQLiteDBAdapter:

public List<User> getUserList() {
    SQLiteDatabase db = getReadableDatabase();
    List<User> userList = new ArrayList<User>();

    String SQL_QUERY = "SELECT * FROM User;";
    Cursor cursor = db.rawQuery(SQL_QUERY, null);
    cursor.moveToFirst();
    while (!cursor.isAfterLast()) {
        User user = new User();
        user.setUserUUID(cursor.getString(0));
        user.setName(cursor.getString(1));
        user.setPassword(cursor.getString(2));
        user.setDateOfBirth(cursor.getString(3));
        user.setStaffNumber(cursor.getString(4));
        user.setActive(cursor.getInt(5));
        user.setUserClass(cursor.getInt(6));
        userList.add(user);
        cursor.moveToNext();
    }
    cursor.close();
    db.close();
    return userList;
}

Я читал, что Mock возвращает пустые заглушки void-методов и возвращает null для любого другого метода. Поскольку я издеваюсь над классом SQLiteDBAdapter, я ожидаю, что вызов getUserList для моего издевательского SQLiteDBAdapter вернет значение null. Мне не совсем понятно, почему он обращается к оригинальному методу. Я предполагаю, что он все еще использует оригинальный SQLiteDBAdapter, а не Mock. Что мне нужно сделать, чтобы исправить это, и как это работает? У меня закончились идеи, поэтому любая помощь приветствуется.


person Frank    schedule 10.04.2013    source источник


Ответы (1)


Насмешка над базой данных для тестирования DAO не имеет для меня никакого смысла. Что вы тестируете? База данных. Зачем его устранять?

Имитация базы данных имеет смысл, когда все ваши тесты DAO пройдены, и пришло время протестировать службу, которая использует ее для выполнения единицы работы. Вы уже протестировали DAO и базу данных, и ваш модульный тест службы не обязательно должен быть интеграционным тестом. Во что бы то ни стало издевайтесь в этом случае.

Я мало что знаю о том, над чем вы издеваетесь, но когда я издеваюсь, это касается интерфейсов, которые я делаю. Макет обеспечивает резервную реализацию для ссылки на тип интерфейса, которую использует мой клиент/тест.

Если вы пытаетесь смоделировать конкретный класс, я бы рекомендовал обернуть этот адаптер внутри реализации на основе интерфейса. Это будет лучшая абстракция, и вам будет легче издеваться над своим интерфейсом.

person duffymo    schedule 10.04.2013
comment
Я хочу проверить свою активность входа в систему. Это действие использует базу данных для получения списка пользователей для AutoCompleteTextview. Я хочу заменить базу данных макетом, чтобы я мог протестировать действие входа (кнопки и т. д.), не завися от базы данных. Я посчитал тестирование некоторых кнопок и EditText хорошим упражнением, так как я играю с robolectric и mockito всего несколько дней. - person Frank; 11.04.2013
comment
Хорошо, это другое — вы тестируете пользовательский интерфейс. Я предполагаю, что вы уже протестировали DAO, поэтому мои комментарии о сервисе актуальны для вас. - person duffymo; 11.04.2013
comment
Насмешка над сторонним кодом имеет для меня весь смысл в мире. Зачем вам тестировать чужой код? И почему вам нужны накладные расходы на ДЕЙСТВИТЕЛЬНО наличие базы данных. Когда вы тестируете DAO, вы не проверяете, работает ли база данных или ее драйвер так, как вы ожидаете, вы проверяете, что ваше взаимодействие с базой данных соответствует вашим ожиданиям. Именно для этого и нужен мокап. например, повторяющиеся обновления не обнаруживаются при попадании в реальную БД, но обычно не ожидаются и не требуются. Это раскрывается макетом. К сожалению, вы не можете контролировать то, что можно высмеивать, поэтому абстрагирование — единственный способ. - person Jason Polites; 17.07.2013
comment
Достаточно справедливо, но я не имею в виду тестирование сторонней базы данных. Оказание услуг? да. Вы не имеете доступа к каким-либо сторонним базам данных напрямую. Те, которые вы бы протестировали, - это ВАШИ базы данных. И я предполагаю, что вы будете тестировать их — никаких макетов — а затем издеваться над ними, когда вы используете сервисы модульного тестирования, которые их используют. - person duffymo; 18.07.2013