Платформы Mobile Backend as a Service (MBaaS) ускоряют разработку, предоставляя готовую backend инфраструктуру. Однако тестирование MBaaS интеграций требует иных стратегий, чем традиционное API тестирование. Это руководство охватывает тестирование Firebase, AWS Amplify и Supabase в мобильных приложениях.
Понимание Вызовов MBaaS Тестирования
Уникальные Характеристики
Характеристика | Традиционное API | MBaaS |
---|---|---|
Аутентификация | Кастомные endpoints | Управляемая (OAuth, Social Login) |
Синхронизация Данных | Request/Response | Listeners в реальном времени |
Offline Режим | Ручная реализация | Встроенное кэширование |
Хранилище Файлов | Кастомные upload endpoints | Управляемые storage buckets |
Push Уведомления | Сторонние сервисы | Интегрированная отправка |
Подход к Тестированию | HTTP mocking | SDK mocking + Эмуляторы |
При тестировании MBaaS платформ тестирование производительности API становится критически важным для мониторинга квот, задержек и эффективности синхронизации в реальном времени.
Firebase Тестирование
Firebase Local Emulator Suite
Настройка:
# Установить Firebase CLI
npm install -g firebase-tools
# Инициализировать Firebase в проекте
firebase init
# Запустить эмуляторы
firebase emulators:start
Android Firebase Testing
Firestore Test:
import com.google.firebase.firestore.FirebaseFirestore
class UserRepositoryTest {
private lateinit var firestore: FirebaseFirestore
@Before
fun setUp() {
firestore = FirebaseFirestore.getInstance().apply {
useEmulator("10.0.2.2", 8080)
firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(false)
.build()
}
}
@Test
fun testCreateUser() = runTest {
val user = User(
id = "test-user-1",
username = "тестовыйпользователь",
email = "test@example.com"
)
userRepository.createUser(user)
val snapshot = firestore.collection("users")
.document("test-user-1")
.get()
.await()
assertTrue(snapshot.exists())
assertEquals("тестовыйпользователь", snapshot.getString("username"))
}
@Test
fun testRealtimeUserUpdates() = runTest {
val updates = mutableListOf<User>()
val job = launch {
userRepository.observeUser("test-user-1").collect { user ->
user?.let { updates.add(it) }
}
}
val user = User(id = "test-user-1", username = "оригинальный")
userRepository.createUser(user)
delay(100)
userRepository.updateUsername("test-user-1", "обновлённый")
delay(100)
job.cancel()
assertEquals(2, updates.size)
assertEquals("оригинальный", updates[0].username)
assertEquals("обновлённый", updates[1].username)
}
@Test
fun testOfflineMode() = runTest {
firestore.firestoreSettings = FirebaseFirestoreSettings.Builder()
.setPersistenceEnabled(true)
.build()
val user = User(id = "offline-user", username = "offline-test")
userRepository.createUser(user)
// Симулировать offline режим
firestore.disableNetwork().await()
// Читать из кэша
val cachedUser = userRepository.getUser("offline-user")
assertNotNull(cachedUser)
assertEquals("offline-test", cachedUser?.username)
// Писать в offline
userRepository.updateUsername("offline-user", "обновлено-offline")
// Включить сеть обратно
firestore.enableNetwork().await()
delay(500)
// Проверить, что offline запись синхронизировалась
val syncedUser = userRepository.getUser("offline-user")
assertEquals("обновлено-offline", syncedUser?.username)
}
}
Понимание мобильного тестирования для iOS и Android является важным при реализации MBaaS решений в различных мобильных окружениях.
AWS Amplify Тестирование
Amplify Mock Backend
Настройка:
# Установить Amplify CLI
npm install -g @aws-amplify/cli
# Инициализировать Amplify
amplify init
# Добавить API
amplify add api
# Запустить mock сервер
amplify mock api
Android Amplify Testing
import com.amplifyframework.api.graphql.model.ModelMutation
import com.amplifyframework.datastore.generated.model.Todo
class TodoRepositoryTest {
@Test
fun testCreateTodo() = runTest {
val todo = Todo.builder()
.name("Test Todo")
.description("Тестирование Amplify")
.build()
val result = todoRepository.createTodo(todo)
assertNotNull(result)
assertEquals("Test Todo", result.name)
}
@Test
fun testQueryTodos() = runTest {
val todo1 = Todo.builder().name("Todo 1").build()
val todo2 = Todo.builder().name("Todo 2").build()
todoRepository.createTodo(todo1)
todoRepository.createTodo(todo2)
val todos = todoRepository.getAllTodos()
assertTrue(todos.size >= 2)
assertTrue(todos.any { it.name == "Todo 1" })
}
}
Supabase Тестирование
Supabase Local Development
Настройка:
# Установить Supabase CLI
npm install -g supabase
# Инициализировать Supabase
supabase init
# Запустить локальный Supabase
supabase start
Android Supabase Testing
import io.github.jan.supabase.postgrest.from
class UserRepositorySupabaseTest {
private val supabase = createTestSupabaseClient()
@Test
fun testCreateUser() = runTest {
val user = UserDto(
username = "тестпользователь",
email = "test@example.com"
)
val created = supabase.from("users")
.insert(user)
.decodeSingle<UserDto>()
assertEquals("тестпользователь", created.username)
assertNotNull(created.id)
}
@Test
fun testRealtimeSubscription() = runTest {
val updates = mutableListOf<UserDto>()
val channel = supabase.realtime.createChannel("users")
channel.postgresChangeFlow<PostgresAction.Insert>(
schema = "public",
table = "users"
).onEach { change ->
updates.add(change.record)
}.launchIn(this)
channel.subscribe()
delay(200)
supabase.from("users").insert(
UserDto(username = "realtime-user", email = "rt@example.com")
)
delay(500)
channel.unsubscribe()
assertTrue(updates.any { it.username == "realtime-user" })
}
}
Лучшие Практики Тестирования
1. Изолировать Тестовые Данные
@Before
fun setUp() {
val testCollectionPrefix = "test_${UUID.randomUUID()}_"
firestore.collection("${testCollectionPrefix}users")
}
@After
fun tearDown() {
deleteTestCollections()
}
2. Мокировать Внешние Зависимости
class UserRepository(
private val firestore: FirebaseFirestore,
private val analytics: Analytics = FirebaseAnalytics.getInstance()
)
// В тестах, инжектить mock analytics
val mockAnalytics = mock<Analytics>()
val repository = UserRepository(firestore, mockAnalytics)
3. Тестировать Переходы Offline/Online
@Test
fun testOnlineOfflineTransition() = runTest {
val user = userRepository.getUser("user-1")
assertNotNull(user)
firestore.disableNetwork().await()
val cachedUser = userRepository.getUser("user-1")
assertEquals(user, cachedUser)
firestore.enableNetwork().await()
val syncedUser = userRepository.getUser("user-1")
assertEquals(user, syncedUser)
}
Безопасность имеет первостепенное значение при работе с аутентификацией и хранением данных на MBaaS платформах. Внедрение практик тестирования безопасности мобильных приложений обеспечивает защиту ваших backend сервисов от распространённых уязвимостей.
CI/CD Интеграция
GitHub Actions с Firebase Emulators
name: MBaaS Tests
on: [push, pull_request]
jobs:
firebase-tests:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Install Firebase CLI
run: npm install -g firebase-tools
- name: Start Firebase Emulators
run: firebase emulators:start --only firestore,auth &
- name: Run Android Tests
run: ./gradlew connectedAndroidTest
Заключение
MBaaS тестирование требует:
- Локальные Эмуляторы: Firebase, Amplify mock, Supabase local
- Real-time Тестирование: Подписки, listeners, синхронизация данных
- Offline Тестирование: Валидация кэша, верификация синхронизации
- Мониторинг Производительности: Отслеживание квот, оптимизация
Стратегия Тестирования:
- Unit тесты с мокированными SDKs
- Интеграционные тесты с эмуляторами
- E2E тесты с staging MBaaS инстансами
- Мониторинг production метрик
MBaaS платформы ускоряют разработку, но требуют дисциплинированного тестирования для обеспечения надёжности, offline поддержки и оптимизации затрат.