### Mocking Dependencies in Android Tests (Kotlin) Source: https://github.com/line/lich/blob/master/component/README.md Provides an example of how to mock dependencies for testing a class using default arguments and Lich's `mockComponent` utility. This setup involves using `Mockito` for mocking and `AndroidJUnit4` for running the tests within an Android environment. Ensure mock components are created before the class under test is instantiated. ```kotlin @RunWith(AndroidJUnit4::class) class FooControllerTest { private lateinit var context: Context private lateinit var mockBarHelper: BarHelper private lateinit var mockBazComponent: BazComponent private lateinit var fooController: FooController @Before fun setUp() { context = ApplicationProvider.getApplicationContext() mockBarHelper = mock() mockBazComponent = mockComponent(BazComponent) fooController = FooController(context, mockBarHelper) } @Test fun testFoo() { // ... } } ``` -------------------------------- ### Mockito-Kotlin Unit Testing Setup - Groovy Source: https://github.com/line/lich/blob/master/component/README.md Sets up dependencies for unit testing with Mockito-Kotlin in an Android project, including Robolectric and AndroidX Test. ```Groovy dependencies { testImplementation 'com.linecorp.lich:component-test-mockitokotlin:x.x.x' testImplementation 'androidx.test:runner:x.x.x' testImplementation 'androidx.test.ext:junit:x.x.x' testImplementation 'org.mockito:mockito-inline:x.x.x' testImplementation 'org.mockito.kotlin:mockito-kotlin:x.x.x' testImplementation 'org.robolectric:robolectric:x.x' androidTestImplementation 'com.linecorp.lich:component-test-mockitokotlin:x.x.x' androidTestImplementation 'androidx.test:runner:x.x.x' androidTestImplementation 'androidx.test.ext:junit:x.x.x' androidTestImplementation 'org.mockito:mockito-android:x.x.x' androidTestImplementation 'org.mockito.kotlin:mockito-kotlin:x.x.x' } ``` -------------------------------- ### MockK Unit Testing Setup - Groovy Source: https://github.com/line/lich/blob/master/component/README.md Configures dependencies for unit testing with MockK in an Android project, including Robolectric and AndroidX Test support. ```Groovy dependencies { testImplementation 'com.linecorp.lich:component-test-mockk:x.x.x' testImplementation 'androidx.test:runner:x.x.x' testImplementation 'androidx.test.ext:junit:x.x.x' testImplementation 'io.mockk:mockk:x.x.x' testImplementation 'org.robolectric:robolectric:x.x' androidTestImplementation 'com.linecorp.lich:component-test-mockk:x.x.x' androidTestImplementation 'androidx.test:runner:x.x.x' androidTestImplementation 'androidx.test.ext:junit:x.x.x' androidTestImplementation 'io.mockk:mockk-android:x.x.x' } ``` -------------------------------- ### Testing with MockK and Lich Components (Kotlin) Source: https://github.com/line/lich/blob/master/component/README.md Provides an example of testing a use case (`SaveFooUseCase`) by mocking its dependencies (`FooRepository`) using MockK and the `mockComponent` function from Lich. This allows for controlled testing of business logic. ```kotlin @RunWith(AndroidJUnit4::class) class SaveFooUseCaseTest { private lateinit var context: Context @Before fun setUp() { context = ApplicationProvider.getApplicationContext() } @Test fun testGetFooFromStorage() { val expected = Foo() val mockFooRepository = mockComponent(FooRepository) { coEvery { findFoo(any()) } returns expected } val saveFooUseCase = SaveFooUseCase(context) val actual = runBlocking { saveFooUseCase.getFooFromStorage("key") } assertEquals(expected, actual) coVerify { mockFooRepository.findFoo(eq("key")) } } } ``` -------------------------------- ### Define a Facade interface for multi-module support Source: https://github.com/line/lich/blob/master/component/README.md Example of defining a Facade interface (`FooModuleFacade`) in the 'base' module to expose functionality from the 'foo' module. This adheres to the Facade pattern for inter-module communication. ```kotlin // "base" module package module.base.facades /** * The Facade of the "foo" module. * https://en.wikipedia.org/wiki/Facade_pattern * * This component defines the API of the "foo" module. */ interface FooModuleFacade { fun launchFooActivity() companion object : ComponentFactory() { override fun createComponent(context: Context): FooModuleFacade = TODO() } } ``` -------------------------------- ### Lazy Lich Component initialization in Activity Source: https://github.com/line/lich/blob/master/component/README.md Example of using lazy Lich component initialization within an Android Activity. The `component` delegate simplifies accessing component instances tied to the Activity's lifecycle. ```kotlin class FooActivity : Activity() { private val fooComponent by component(FooComponent) // snip... } ``` -------------------------------- ### Gradle Dependencies for Lich ViewModel with Mockito-Kotlin Source: https://github.com/line/lich/blob/master/viewmodel/README.md This snippet outlines the Gradle dependencies for integrating Lich ViewModel with a testing setup that utilizes Mockito-Kotlin. It covers the core library, Compose support, and the necessary testing libraries for Mockito-Kotlin. ```groovy dependencies { implementation 'com.linecorp.lich:viewmodel:x.x.x' // For Jetpack Compose implementation 'com.linecorp.lich:viewmodel-compose:x.x.x' testImplementation 'com.linecorp.lich:viewmodel-test-mockitokotlin:x.x.x' testImplementation 'androidx.test:runner:x.x.x' testImplementation 'androidx.test.ext:junit:x.x.x' testImplementation 'org.mockito:mockito-inline:x.x.x' testImplementation 'org.mockito.kotlin:mockito-kotlin:x.x.x' testImplementation 'org.robolectric:robolectric:x.x' androidTestImplementation 'com.linecorp.lich:viewmodel-test-mockitokotlin:x.x.x' androidTestImplementation 'androidx.test:runner:x.x.x' androidTestImplementation 'androidx.test.ext:junit:x.x.x' androidTestImplementation 'org.mockito:mockito-android:x.x.x' androidTestImplementation 'org.mockito.kotlin:mockito-kotlin:x.x.x' } ``` -------------------------------- ### Execute GET request with OkHttp coroutine extension in Kotlin Source: https://context7.com/line/lich/llms.txt Provides a suspending function fetchContent that performs a simple GET request using OkHttp. It automatically checks for successful responses and returns the response body as a string. Throws IOException on HTTP errors. ```Kotlin suspend fun fetchContent(url: String): String {\n val request = Request.Builder().url(url).build()\n\n return okHttpClient.call(request) { response ->\n if (!response.isSuccessful) {\n throw IOException("HTTP ${response.code}: ${response.message}")\n }\n checkNotNull(response.body).string()\n }\n} ``` -------------------------------- ### Declare a Room Database as a Lich Component Source: https://github.com/line/lich/blob/master/component/README.md Example of declaring a Room database as a Lich component. It uses `Room.databaseBuilder` within the `createComponent` method of the companion object. ```kotlin @Database(entities = [Foo::class], version = 1) abstract class FooDatabase : RoomDatabase() { abstract val fooDao: FooDao companion object : ComponentFactory() { override fun createComponent(context: Context): FooDatabase = Room.databaseBuilder(context, FooDatabase::class.java, "foo_db").build() } } ``` -------------------------------- ### Implement GlobalContext for Global Component Access in Kotlin Source: https://github.com/line/lich/blob/master/component/README.md Provides a solution to access components globally without explicitly passing a Context every time. It requires initial setup with the Application context and offers methods for both eager and lazy component retrieval. ```kotlin object GlobalContext { private lateinit var application: Application fun setup(application: Application) { this.application = application } fun getComponent(factory: ComponentFactory): T = application.getComponent(factory) fun component(factory: ComponentFactory): Lazy = componentLazy(factory) { application } } class MyApplication : Application() { override fun onCreate() { super.onCreate() GlobalContext.setup(this) } } ``` -------------------------------- ### Initialize Fragment ViewModel with SavedState using setViewModelArgs Source: https://github.com/line/lich/blob/master/viewmodel/README.md Provides an example of initializing a Fragment's ViewModel using Lich SavedState arguments. This method directly uses `setViewModelArgs` on the Fragment instance to configure the `SavedStateHandle` for the ViewModel before it's accessed. ```kotlin class FooFragment : Fragment() { private val fooViewModel by viewModel(FooViewModel) // snip... } val fooFragment = FooFragment().also { // This `FooViewModelArgs` is used to initialize the `savedStateHandle` of `FooFragment.fooViewModel`. it.setViewModelArgs(FooViewModelArgs(userName = "John", attachment = null, message = "Hello.")) } ``` -------------------------------- ### Fetch Content as String using OkHttp Source: https://github.com/line/lich/blob/master/okhttp/README.md A suspending function to fetch the content of a given URL as a String. It uses OkHttp's call extension to send a GET request and handles successful responses by returning the body as a string. It throws a ResponseStatusException for non-successful HTTP codes. ```kotlin suspend fun fetchContentAsString(url: String): String { val request = Request.Builder().url(url).build() return okHttpClient.call(request) { response -> if (!response.isSuccessful) { throw ResponseStatusException(response.code) } checkNotNull(response.body).string() } } ``` -------------------------------- ### Get Fragment ViewModel instance with Kotlin Source: https://github.com/line/lich/blob/master/viewmodel/README.md Gets a ViewModel instance associated with a Fragment using the viewModel delegate. The ViewModel lifecycle is tied to the Fragment's lifecycle. Works with AndroidX Fragment class. ```kotlin class FooFragment : Fragment() { // An instance of FooViewModel associated with FooFragment. private val fooViewModel by viewModel(FooViewModel) // snip... } ``` -------------------------------- ### Set up Lich SavedState with kapt Source: https://github.com/line/lich/blob/master/savedstate/README.md Alternative configuration using kapt instead of KSP. Includes necessary plugin and dependency declarations for Kotlin annotation processing. ```groovy plugins { id 'org.jetbrains.kotlin.kapt' } dependencies { implementation 'com.linecorp.lich:savedstate:x.x.x' kapt 'com.linecorp.lich:savedstate-compiler:x.x.x' } ``` -------------------------------- ### Create Multi-Module Component with delegateCreation (Kotlin) Source: https://context7.com/line/lich/llms.txt Demonstrates how to create a component that spans multiple modules using named factory classes and delegateCreation. It includes the repository interface, the factory implementation, and usage within a ViewModel. This approach facilitates cross-module component resolution. ```kotlin // In base module interface CounterRepository { suspend fun getCounter(counterName: String): Int suspend fun storeCounter(counterName: String, value: Int) companion object : ComponentFactory() { override fun createComponent(context: Context): CounterRepository = delegateCreation(context, "com.example.impl.CounterRepositoryFactory") } } // In implementation module class CounterRepositoryFactory : DelegatedComponentFactory() { override fun createComponent(context: Context): CounterRepository = CounterRepositoryImpl(context) } private class CounterRepositoryImpl( private val context: Context ) : CounterRepository { private val preferences = context.getSharedPreferences("counters", Context.MODE_PRIVATE) override suspend fun getCounter(counterName: String): Int = withContext(Dispatchers.IO) { preferences.getInt(counterName, 0) } override suspend fun storeCounter(counterName: String, value: Int) { withContext(Dispatchers.IO) { preferences.edit().putInt(counterName, value).apply() } } } // Usage class CounterViewModel(context: Context) : ViewModel() { private val counterRepository by context.component(CounterRepository) suspend fun incrementCounter(name: String) { val current = counterRepository.getCounter(name) counterRepository.storeCounter(name, current + 1) } } ``` -------------------------------- ### Test Components with MockK (Kotlin) Source: https://context7.com/line/lich/llms.txt Shows how to unit test components using MockK with the Lich component-test-mockk module. It covers mocking and spying on components to isolate dependencies and verify interactions. This enables testing component logic without relying on actual implementations. ```kotlin import com.linecorp.lich.component.test.mockk.mockComponent import com.linecorp.lich.component.test.mockk.spyComponent import io.mockk.coEvery import io.mockk.coVerify @RunWith(AndroidJUnit4::class) class FooViewModelTest { @Test fun testLoadData() = runTest { // Mock a component val mockRepository = mockComponent(FooRepository) { coEvery { fetchData(any()) } returns FooData("test", 123) } val viewModel = FooViewModel(ApplicationProvider.getApplicationContext()) viewModel.loadData("foo") coVerify { mockRepository.fetchData("foo") } assertEquals("test", viewModel.data.value?.name) } @Test fun testWithSpy() = runTest { // Spy on real component with partial mocking val spyRepository = spyComponent(FooRepository) { coEvery { fetchData("error") } throws IOException("Network error") } val viewModel = FooViewModel(ApplicationProvider.getApplicationContext()) // Normal call goes to real implementation viewModel.loadData("normal") assertNotNull(viewModel.data.value) // Mocked call throws exception assertFailsWith { viewModel.loadData("error") } } } ``` -------------------------------- ### Delegate Component Creation using ServiceLoader and AutoService (Kotlin) Source: https://github.com/line/lich/blob/master/component/README.md Delegates component creation to ServiceLoader, recommended with the AutoService library. Requires adding AutoService dependencies to build.gradle and annotating the implementation class with @AutoService. The implementation class must have a public empty constructor and optionally implement ServiceLoaderComponent for context initialization. ```groovy apply plugin: 'kotlin-kapt' dependencies { compileOnly 'com.google.auto.service:auto-service-annotations:x.x' kapt 'com.google.auto.service:auto-service:x.x' } ``` ```kotlin // "base" module package module.base.facades interface FooModuleFacade { fun launchFooActivity() companion object : ComponentFactory() { override fun createComponent(context: Context): FooModuleFacade = delegateToServiceLoader(context) } } ``` ```kotlin // "foo" module package module.foo // Declare this class as an implementation of `FooModuleFacade`. @AutoService(FooModuleFacade::class) class FooModuleFacadeImpl : FooModuleFacade, ServiceLoaderComponent { private lateinit var context: Context // The class instantiated by `delegateToServiceLoader` must have a public empty constructor. // If the class requires a `context`, implement the `ServiceLoaderComponent` interface and // override the `init(context)` function. override fun init(context: Context) { this.context = context } override fun launchFooActivity() { // snip... } } ``` -------------------------------- ### Get Activity ViewModel instance with Kotlin Source: https://github.com/line/lich/blob/master/viewmodel/README.md Obtains a ViewModel instance associated with an Activity using the viewModel delegate. This creates a scoped ViewModel that lives as long as the Activity. Requires AppCompatActivity from AndroidX. ```kotlin class FooActivity : AppCompatActivity() { // An instance of FooViewModel associated with FooActivity. private val fooViewModel by viewModel(FooViewModel) // snip... } ``` -------------------------------- ### Set up Lich SavedState with KSP Source: https://github.com/line/lich/blob/master/savedstate/README.md Configure your project to use Lich SavedState with KSP. Requires adding KSP plugin and dependencies for implementation and compilation. ```groovy plugins { id 'com.google.devtools.ksp' version 'x.x.x-x.x.x' } dependencies { implementation 'com.linecorp.lich:savedstate:x.x.x' ksp 'com.linecorp.lich:savedstate-compiler:x.x.x' } ``` -------------------------------- ### Access Components using GlobalContext in Kotlin Source: https://github.com/line/lich/blob/master/component/README.md Shows how to retrieve components using the previously defined GlobalContext object. It illustrates both eager instantiation and lazy initialization of components, simplifying access patterns. ```kotlin val eagerFooComponent: FooComponent = GlobalContext.getComponent(FooComponent) val lazyFooComponent: FooComponent by GlobalContext.component(FooComponent) ``` -------------------------------- ### Lazy Lich Component initialization in Fragment Source: https://github.com/line/lich/blob/master/component/README.md Demonstrates lazy Lich component initialization within an Android Fragment using the `component` delegate. This pattern is consistent with its usage in Activities. ```kotlin class FooFragment : Fragment() { private val fooComponent by component(FooComponent) // snip... } ``` -------------------------------- ### Implement FooServiceClient using AbstractThriftServiceClient Source: https://github.com/line/lich/blob/master/thrift/README.md This Kotlin code demonstrates how to implement a Thrift service client by extending AbstractThriftServiceClient. It configures the client with OkHttp and an endpoint URL, and defines methods for making RPC calls like `ping` and `callFoo`. ```kotlin class FooServiceClient( override val okHttpClient: OkHttpClient, override val endpointUrl: HttpUrl ) : AbstractThriftServiceClient() { override val thriftClientFactory: ThriftClientFactory = ThriftClientFactory(FooService.Client.Factory()) suspend fun ping() = call({ send_ping() }, { recv_ping() }) suspend fun callFoo(id: Long, name: String, param: FooParam): FooResponse = call({ send_callFoo(id, name, param) }, { recv_callFoo() }) } val fooServiceClient = FooServiceClient(OkHttpClient(), "https://api.example.com/foo".toHttpUrl()) try { val response = fooServiceClient.callFoo(123, "foobar", FooParam(4)) println("response = $response") } catch (e: TException) { println("fooService.callFoo() failed: $e") } ``` -------------------------------- ### Get Activity-shared ViewModel in Fragment with Kotlin Source: https://github.com/line/lich/blob/master/viewmodel/README.md Retrieves a ViewModel associated with the hosting Activity using activityViewModel delegate. Enables data sharing between Fragments and their parent Activity. The ViewModel persists across Fragment recreations but is scoped to the Activity. ```kotlin class FooFragment : Fragment() { // A shared instance of FooViewModel associated with the Activity hosting this FooFragment. private val fooActivityViewModel by activityViewModel(FooViewModel) // snip... } ``` -------------------------------- ### Gradle Dependencies for Lich ViewModel with MockK Source: https://github.com/line/lich/blob/master/viewmodel/README.md This snippet shows the Gradle dependencies required to set up the Lich ViewModel library and its associated testing tools using MockK for mocking. It includes dependencies for the core library, Jetpack Compose integration, and various testing utilities. ```groovy dependencies { implementation 'com.linecorp.lich:viewmodel:x.x.x' // For Jetpack Compose implementation 'com.linecorp.lich:viewmodel-compose:x.x.x' testImplementation 'com.linecorp.lich:viewmodel-test-mockk:x.x.x' testImplementation 'androidx.test:runner:x.x.x' testImplementation 'androidx.test.ext:junit:x.x.x' testImplementation 'io.mockk:mockk:x.x.x' testImplementation 'org.robolectric:robolectric:x.x' androidTestImplementation 'com.linecorp.lich:viewmodel-test-mockk:x.x.x' androidTestImplementation 'androidx.test:runner:x.x.x' androidTestImplementation 'androidx.test.ext:junit:x.x.x' androidTestImplementation 'io.mockk:mockk-android:x.x.x' } ``` -------------------------------- ### Accessing a multi-module Facade component Source: https://github.com/line/lich/blob/master/component/README.md Demonstrates how to obtain and use a Lich component that acts as a Facade to another module. This involves using `context.getComponent` with the Facade interface. ```kotlin // Call some feature of the "foo" module. val fooModuleFacade = context.getComponent(FooModuleFacade) fooModuleFacade.launchFooActivity() ``` -------------------------------- ### Initialize ViewModel using SavedStateViewModelFactory (Kotlin) Source: https://github.com/line/lich/blob/master/savedstate/README.md This snippet shows an alternative way to initialize a ViewModel using the `SavedStateViewModelFactory`. It passes the generated ViewModelArgs as a Bundle to the factory, which then sets up the SavedStateHandle. ```kotlin class FooFragment : Fragment() { private val fooViewModel: FooViewModel by viewModels { SavedStateViewModelFactory( requireActivity().application, this, FooViewModelArgs(userName = "John", attachment = null, message = "Hello.").toBundle() ) } // snip... } ``` -------------------------------- ### Get Navigation Graph ViewModel in Fragment with Kotlin Source: https://github.com/line/lich/blob/master/viewmodel/README.md Obtains a ViewModel scoped to a specific navigation graph using navGraphViewModel delegate. Requires AndroidX Navigation library. The ViewModel is shared among all destinations in the specified navigation graph and survives configuration changes. ```kotlin class FooFragment : Fragment() { // A shared instance of FooViewModel scoped to the `foo_nav_graph` navigation graph. private val fooNavGraphViewModel by navGraphViewModel(FooViewModel, R.id.foo_nav_graph) // snip... } ``` -------------------------------- ### Multi-Module Component with ServiceLoader in Kotlin Source: https://context7.com/line/lich/llms.txt Shows how to implement multi-module components using ServiceLoader and AutoService annotation. Defines a facade interface in the base module and implements it in a feature module. Enables components to work across Dynamic Feature Modules with proper initialization and service loading. ```kotlin interface FooModuleFacade { fun launchFooActivity(context: Context) fun getFooData(): String companion object : ComponentFactory() { override fun createComponent(context: Context): FooModuleFacade = delegateToServiceLoader(context) } } @AutoService(FooModuleFacade::class) class FooModuleFacadeImpl : FooModuleFacade, ServiceLoaderComponent { private lateinit var context: Context override fun init(context: Context) { this.context = context } override fun launchFooActivity(context: Context) { context.startActivity(Intent(context, FooActivity::class.java)) } override fun getFooData(): String = "Foo Data" } class MainActivity : AppCompatActivity() { private val fooModuleFacade by component(FooModuleFacade) override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) findViewById