kotlin
228 lines · 2 tabs
Alex Chen
Jan 2026
2 tabs
package com.example.myapp.data.repository
import com.example.myapp.data.local.PostDao
import com.example.myapp.data.local.PostEntity
import com.example.myapp.data.remote.ApiService
import com.example.myapp.models.Post
import io.mockk.*
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.runTest
import org.junit.After
import org.junit.Before
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertTrue
@OptIn(ExperimentalCoroutinesApi::class)
class PostRepositoryTest {
private lateinit var repository: PostRepositoryImpl
private lateinit var apiService: ApiService
private lateinit var postDao: PostDao
private lateinit var mapper: PostMapper
@Before
fun setup() {
apiService = mockk()
postDao = mockk(relaxed = true)
mapper = PostMapper()
repository = PostRepositoryImpl(apiService, postDao, mapper)
}
@After
fun tearDown() {
unmockkAll()
}
@Test
fun `fetchPosts should return success when API call succeeds`() = runTest {
// Given
val mockPosts = listOf(
Post(id = 1, title = "Test Post", body = "Content",
authorId = 1, createdAt = 0L)
)
val response = PostsResponse(posts = mockPosts, meta = Meta(1, 20, 1))
coEvery { apiService.getPosts(any(), any()) } returns response
// When
val result = repository.fetchPosts()
// Then
assertTrue(result.isSuccess)
assertEquals(mockPosts, result.getOrNull())
coVerify { postDao.insertAll(any()) }
}
@Test
fun `fetchPosts should return cached data when API call fails`() = runTest {
// Given
val cachedEntities = listOf(
PostEntity(id = 1, title = "Cached", body = "Content",
authorId = 1, createdAt = 0L)
)
coEvery { apiService.getPosts(any(), any()) } throws Exception("Network error")
coEvery { postDao.getAllPosts() } returns cachedEntities
// When
val result = repository.fetchPosts()
// Then
assertTrue(result.isSuccess)
val posts = result.getOrNull()
assertEquals(1, posts?.size)
assertEquals("Cached", posts?.first()?.title)
}
@Test
fun `observePosts should emit sorted posts from DAO`() = runTest {
// Given
val entities = listOf(
PostEntity(id = 1, title = "Old", body = "Content",
authorId = 1, createdAt = 1000L),
PostEntity(id = 2, title = "New", body = "Content",
authorId = 1, createdAt = 2000L)
)
every { postDao.observePosts() } returns flowOf(entities)
// When
val posts = mutableListOf<List<Post>>()
repository.observePosts().collect { posts.add(it) }
// Then
assertEquals(1, posts.size)
assertEquals(2, posts.first().size)
assertEquals("New", posts.first().first().title)
}
@Test
fun `createPost should call API and cache result`() = runTest {
// Given
val post = Post(id = 0, title = "New Post", body = "Content",
authorId = 1, createdAt = 0L)
val createdPost = post.copy(id = 123)
val response = PostResponse(post = createdPost)
val requestSlot = slot<CreatePostRequest>()
coEvery {
apiService.createPost(capture(requestSlot))
} returns response
// When
val result = repository.createPost(post)
// Then
assertTrue(result.isSuccess)
assertEquals("New Post", requestSlot.captured.title)
coVerify { postDao.insert(any()) }
}
}
package com.example.myapp.ui
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.example.myapp.data.repository.PostRepository
import com.example.myapp.models.Post
import io.mockk.*
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.flow.flowOf
import kotlinx.coroutines.test.*
import org.junit.After
import org.junit.Before
import org.junit.Rule
import org.junit.Test
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
@OptIn(ExperimentalCoroutinesApi::class)
class PostViewModelTest {
@get:Rule
val instantExecutorRule = InstantTaskExecutorRule()
private val testDispatcher = StandardTestDispatcher()
private lateinit var viewModel: PostViewModel
private lateinit var repository: PostRepository
@Before
fun setup() {
Dispatchers.setMain(testDispatcher)
repository = mockk()
viewModel = PostViewModel(repository)
}
@After
fun tearDown() {
Dispatchers.resetMain()
unmockkAll()
}
@Test
fun `initial state should be loading`() = runTest {
val state = viewModel.uiState.value
assertTrue(state.posts.isEmpty())
}
@Test
fun `loadPosts should update state with posts on success`() = runTest {
// Given
val mockPosts = listOf(
Post(id = 1, title = "Test", body = "Content",
authorId = 1, createdAt = 0L)
)
coEvery { repository.fetchPosts() } returns Result.success(mockPosts)
// When
viewModel.loadPosts()
testDispatcher.scheduler.advanceUntilIdle()
// Then
val state = viewModel.uiState.value
assertEquals(mockPosts, state.posts)
assertFalse(state.isLoading)
assertEquals(null, state.error)
}
@Test
fun `loadPosts should update state with error on failure`() = runTest {
// Given
val errorMessage = "Network error"
coEvery {
repository.fetchPosts()
} returns Result.failure(Exception(errorMessage))
// When
viewModel.loadPosts()
testDispatcher.scheduler.advanceUntilIdle()
// Then
val state = viewModel.uiState.value
assertFalse(state.isLoading)
assertEquals(errorMessage, state.error)
}
@Test
fun `observePosts should collect posts from repository`() = runTest {
// Given
val mockPosts = listOf(
Post(id = 1, title = "Test", body = "Content",
authorId = 1, createdAt = 0L)
)
every { repository.observePosts() } returns flowOf(mockPosts)
// Re-create ViewModel to trigger init block
viewModel = PostViewModel(repository)
testDispatcher.scheduler.advanceUntilIdle()
// Then
val state = viewModel.uiState.value
assertEquals(mockPosts, state.posts)
}
}
2 files · kotlin
Explain with highlit
Unit testing verifies individual components in isolation. I use JUnit 5 or JUnit 4 as the test framework with @Test annotations. MockK provides Kotlin-friendly mocking—mockk<T>() creates mocks, every { } stubs behavior, verify { } confirms calls. Coroutines testing uses runTest or runBlockingTest with TestDispatchers. ViewModels test using InstantTaskExecutorRule for LiveData. Repository tests mock DAOs and API services. coEvery handles suspend functions. slot() captures arguments. Assertions use assertEquals, assertTrue, or libraries like Truth or AssertJ. Testing ensures code correctness and enables refactoring confidence.
Related snips
ruby
class CommentsController < ApplicationController
before_action :set_post
def create
@comment = @post.comments.build(comment_params)
System test: asserting Turbo Stream responses
rails
hotwire
turbo
by codesnips
4 tabs
kotlin
package com.example.myapp
import android.app.Application
import dagger.hilt.android.HiltAndroidApp
@HiltAndroidApp
Dependency injection with Hilt
kotlin
android
hilt
by Alex Chen
3 tabs
kotlin
package com.example.myapp.ui
import androidx.lifecycle.*
import kotlinx.coroutines.launch
class UserViewModel(
LiveData transformations and mediators
kotlin
android
livedata
by Alex Chen
1 tab
rust
use my_crate::add;
#[test]
fn test_public_api() {
assert_eq!(add(3, 4), 7);
}
Integration tests in tests/ directory
rust
testing
integration
by Marcus Chen
1 tab
kotlin
package com.example.myapp.utils
import android.os.Build
import android.os.StrictMode
import android.os.Trace
import timber.log.Timber
Performance optimization and profiling
kotlin
android
performance
by Alex Chen
2 tabs
kotlin
package com.example.myapp.widget
import android.app.PendingIntent
import android.appwidget.AppWidgetManager
import android.appwidget.AppWidgetProvider
import android.content.Context
App widgets for home screen
kotlin
android
widget
by Alex Chen
2 tabs
Share this code
Here's the card — post it anywhere.