2013-04-10 31 views
7

W ciągu ostatnich kilku dni zacząłem grać z roboguice, robolectric i mockito. Mam małą aplikację na Androida z ekranem logowania zawierającym AutoCompleteTextView do szybszego wpisywania nazwy użytkownika. Nazwy użytkownika dla AutoCompleteTextView są przechowywane w bazie danych SQLite.
Prześmiewanie bazy danych SQLite podczas testowania aktywności za pomocą Robolectric

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)); 
    } 
... 
} 

Chcę przetestować główną działalność za pomocą robolectric, starając się szydzić bazy danych z Mockito. To jest mój test-klasa:

@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); 
} 
} 

Wywołanie mainActivity.onCreate (null); rozpoczyna kaskadę błędów, kończąc na linii kursor kursora = db.rawQuery (SQL_QUERY, null); mojego getUserList-metody w moim 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; 
} 

czytałem, że Mock powraca puste odcinki z pustych przestrzeni metod i zwraca NULL w przypadku każdej innej metody. Ponieważ kpię z klasy SQLiteDBAdapter, oczekuję, że wywołanie metody getUserList na moim wyśmianym SQLiteDBAdapter zwróci wartość null. Nie jest dla mnie jasne, dlaczego ma dostęp do oryginalnej metody. Sądzę, że nadal używa oryginalnego SQLiteDBAdapter, a nie makiety. Co muszę zrobić, aby to naprawić i jak to działa? Zabrakło mi pomysłów, więc każda pomoc jest doceniana.

Odpowiedz

2

Prześmiewanie bazy danych w celu przetestowania DAO nie ma dla mnie żadnego sensu. Co testujesz? Baza danych. Po co to eliminować?

Prześmiewanie bazy danych ma sens po przejściu wszystkich testów DAO i nadszedł czas, aby przetestować usługę, która umożliwia użytkownikom wykonanie jednostki pracy. Przetestowano już DAO i bazę danych, a test jednostki serwisowej nie musi być testem integracyjnym. W każdym razie zaszufladkuj w tej sprawie.

Nie wiem zbyt wiele na temat tego, co kpisz, ale kiedy kpię, mówię o interfejsach mojego autorstwa. The mock zapewnia implementację stand-in dla interfejsu referencyjnego, którego używa mój klient/test.

Jeśli próbujesz wyśmiać konkretną klasę, radzę zawinąć ten adapter w implementację opartą na interfejsie. To będzie lepsza abstrakcja, a będziesz miał łatwiejszy czas na kpiny z interfejsu.

+0

Chcę przetestować moją aktywność logowania. Ta aktywność korzysta z bazy danych, aby uzyskać listę userList dla widoku AutoCompleteTextview. Chcę zastąpić bazę danych makietą, aby przetestować aktywność logowania (przyciski itp.) Bez uzależnienia od bazy danych. Rozważałem przetestowanie niektórych przycisków i EditTexta, ponieważ gram na robolektryku i mockito tylko przez kilka dni. – Frank

+0

OK, to coś innego - testujesz interfejs użytkownika. Zakładam, że już przetestowałeś DAO, więc moje komentarze na temat usługi trzymają się za Ciebie. – duffymo

+0

Kpiny z kodu strony trzeciej mają dla mnie sens. Dlaczego miałbyś testować czyjś kod? I dlaczego chcesz narzut na RZECZYWIŚCIE mając bazę danych. Podczas testowania DAO nie testujesz, czy baza danych lub jej sterownik działają zgodnie z oczekiwaniami, testujesz, że twoja interakcja z bazą danych przebiega tak, jak oczekujesz. Właśnie do tego służy fałszywy przykład. np. zduplikowane aktualizacje nie są odkrywane podczas uderzania w prawdziwą bazę danych, ale zazwyczaj nie są oczekiwane lub poszukiwane. Zostało to odkryte przez próbę. Niestety nie możesz kontrolować, co jest możliwe do wykonania, więc abstrahowanie jest jedyną drogą. –