I have been using Dagger Android for a while, and now I want to inject a MockModule for testing purposes, and I do not know how to get it. I have seen on some posts that they call something like:
DaggerAppComponent.builder()
.dataModule(myMockModule)
.create(this).inject(this)
But I have this configuration:
#Singleton
#Component(modules = [
AndroidSupportInjectionModule::class,
ActivitiesBuilderModule::class,
AppModule::class,
DataModule::class
])
internal interface AppComponent : AndroidInjector<CbvApplication> {
#Component.Builder
abstract class Builder : AndroidInjector.Builder<CbvApplication>()
}
and when I create the application, the DaggerAppComponent.Builder does not provides the setters for the individual modules. That is nice cause in the app code I do not have to worry about it, but on testing, I want to inject my mock objects through mockComponents / modules.
Anyone can point me in the right direction???
As far as I know, I am not sure we can mock the whole module all together, but we can mock dependencies provided by module.
I have achieved this like, I need to mock DataModule for UI Testing so I have created this TestDataModule and provided mocks for the dependency.
import com.nhaarman.mockito_kotlin.mock
import dagger.Module
import dagger.Provides
import javax.inject.Singleton
#Module
class TestDataModule {
#Provides
#Singleton
fun providesDataRepository(): DataRepository {
return mock()
}
}
Here is TestApplicationModule
#Module
abstract class TestApplicationModule {
#Binds
abstract fun bindContext(application: Application): Context
}
And created TestApplicationComponent which will take the required modules
#Singleton
#Component(modules = [
(AndroidSupportInjectionModule::class),
(TestApplicationModule::class),
(UIModule::class),
(PresentationModule::class),
(TestDataModule::class)])
interface TestApplicationComponent {
// Here you can add additional direct mock
// classes to access them directly from component reference
fun dataRepository(): DataRepository
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): TestApplicationComponent.Builder
fun build(): TestApplicationComponent
}
fun inject(app: TestAppplication)
}
I had to test UI using Android JUnit Test runner and espresso, So I used UIModule and Presentation Module as it is (Cannot mock as wanted to test). So have to mock other dependencies which are not part of that UI Unit tests like DataRepository
You can add other modules like CacheModule and RemoteModules as mocks as they don't play any role in UI Unit testing.
Finally, Create DaggerTestApplicationComponent in TestApplication like this,
class TestApplication : Application(), HasActivityInjector {
#Inject lateinit var activityInjector: DispatchingAndroidInjector<Activity>
private lateinit var appComponent: TestApplicationComponent
override fun onCreate() {
super.onCreate()
appComponent = DaggerTestApplicationComponent.builder()
.application(this)
.build()
appComponent.inject(this)
}
override fun activityInjector(): AndroidInjector<Activity> = activityInjector
}
So now DaggerTestApplicationComponent will generate required dependency graph.
Note: It is required to stub all the methods called on mocked dependencies
Related
I have built a Dynamic feature module sample with Fragments, sub components and dependent components based on plaid app, if you wish to check out here is the link. Now, i'm trying to convert it to Dagger Hilt using the official android document.
In core module which is the library module, app module and dynamic feature modules depend on
#Singleton
#Component(modules = [CoreModule::class])
interface CoreComponent {
/*
Provision methods to provide dependencies below to components that depends on
CoreComponent
*/
fun coreDependency(): CoreDependency
fun coreCameraDependency(): CoreCameraDependency
fun corePhotoDependency(): CorePhotoDependency
fun coreActivityDependency(): CoreActivityDependency
#Component.Factory
interface Factory {
fun create(#BindsInstance application: Application): CoreComponent
}
}
and it's module
#Module(includes = [CoreProvideModule::class])
abstract class CoreModule {
#Binds
abstract fun bindContext(application: Application): Context
}
#Module
object CoreProvideModule {
#Singleton
#Provides
fun provideCoreDependency(application: Application) = CoreDependency(application)
#ActivityScope
#Provides
fun provideCoreActivityDependency(context: Context) = CoreActivityDependency(context)
#Provides
fun provideCoreCameraDependency(): CoreCameraDependency = CoreCameraDependency()
#Provides
fun provideCorePhotoDependency(): CorePhotoDependency = CorePhotoDependency()
}
How is CoreComponent migrated? Do provision methods still stay and i only change
#Singleton
#DefineComponent
or
#Singleton
#DefineComponent(parent = ApplicationComponent.class)
for CoreModule i guess i only change
#EntryPoint
#InstallIn(CoreComponent::class)
or is this for adding provision methods in CoreComponent?
How do i create sub-component in app module?
If anyone has a sample with dynamic feature fragments and hilt, or tutorial to build, it would be more than welcome. I'm just working on it at the moment, if i figure it out i would post an answer
I finally figured it out.
For an app structure
FeatureCamera FeaturePhotos (Dynamic Feature Modules)
| | |
| ----App
| |
core(android-library)
Camera dynamic feature module dependencies from core module, Photo dynamic feature module dependencies from app.
First create a CoreModule in library module
#InstallIn(ApplicationComponent::class)
#Module
class CoreModule {
#Singleton
#Provides
fun provideCoreDependency(application: Application) = CoreDependency(application)
#Provides
fun provideCoreActivityDependency(context: Application) = CoreActivityDependency(context)
#Provides
fun provideCoreCameraDependency(): CoreCameraDependency = CoreCameraDependency()
#Provides
fun provideCorePhotoDependency(): CorePhotoDependency = CorePhotoDependency()
}
An interface with #EntryPoint is required to with provision methods defined in this interface, if you don't define a method for that dependency you cannot inject it even though there is a #Provides method for it. These are mock dependencies that take application or context as only parameter.
#EntryPoint
#InstallIn(ApplicationComponent::class)
interface CoreComponent {
/*
Provision methods to provide dependencies to components that depend on this component
*/
fun coreDependency(): CoreDependency
fun coreActivityDependency(): CoreActivityDependency
fun coreCameraDependency(): CoreCameraDependency
fun corePhotoDependency(): CorePhotoDependency
}
In camera dynamic feature module, create another module for the dependency based inside of this dynamic feature module.
#InstallIn(FragmentComponent::class)
#Module(includes = [CameraBindModule::class])
class CameraModule {
#Provides
fun provideCameraObject(context: Context) = CameraObject(context)
}
#InstallIn(FragmentComponent::class)
#Module
abstract class CameraBindModule {
#Binds
abstract fun bindContext(application: Application): Context
}
And component to inject dependencies to Fragments or Activities in this DFM.
#Component(
dependencies = [CoreComponent::class],
modules = [CameraModule::class]
)
interface CameraComponent {
fun inject(cameraFragment1: CameraFragment1)
fun inject(cameraFragment2: CameraFragment2)
fun inject(cameraActivity: CameraActivity)
#Component.Factory
interface Factory {
fun create(coreComponent: CoreComponent, #BindsInstance application: Application): CameraComponent
}
}
If injected to Activity call in `onCreate()`
DaggerCameraComponent.factory().create(
EntryPointAccessors.fromApplication(
applicationContext,
CoreComponent::class.java
),
application
)
.inject(this)
For injecting to Fragment call in `onCreate()`
DaggerCameraComponent.factory().create(
EntryPointAccessors.fromApplication(
requireActivity().applicationContext,
CoreComponent::class.java
),
requireActivity().application
)
.inject(this)
The trick is here to get dependency interface annotated with `#EntryPoint`
using `EntryPointAccessors.fromApplication()`
Also created Activity based dependencies in app module
**MainActivityModule.kt**
#InstallIn(ActivityComponent::class)
#Module(includes = [MainActivityBindModule::class])
class MainActivityModule {
#Provides
fun provideToastMaker(application: Application) = ToastMaker(application)
#ActivityScoped
#Provides
fun provideMainActivityObject(context: Context) = MainActivityObject(context)
}
#InstallIn(ActivityComponent::class)
#Module
abstract class MainActivityBindModule {
#Binds
abstract fun bindContext(application: Application): Context
}
And only intend to inject these dependencies to Photos dynamic feature module so named it as `PhotoDependencies`
#EntryPoint
#InstallIn(ActivityComponent::class)
interface PhotoModuleDependencies {
fun toastMaker(): ToastMaker
fun mainActivityObject(): MainActivityObject
}
In Photos dynamic feature module create dagger module named `PhotoModule`
#InstallIn(FragmentComponent::class)
#Module(includes = [PhotoBindModule::class])
class PhotoModule {
#Provides
fun providePhotoObject(application: Application): PhotoObject = PhotoObject(application)
}
#InstallIn(FragmentComponent::class)
#Module
abstract class PhotoBindModule {
#Binds
abstract fun bindContext(application: Application): Context
}
And component
#Component(
dependencies = [PhotoModuleDependencies::class],
modules = [PhotoModule::class]
)
interface PhotoComponent {
fun inject(photosFragment1: PhotoFragment1)
fun inject(photosFragment2: PhotoFragment2)
#Component.Factory
interface Factory {
fun create(photoModuleDependencies: PhotoModuleDependencies,
#BindsInstance application: Application): PhotoComponent
}
}
And inject to fragments with
DaggerPhotoComponent.factory().create(
EntryPointAccessors.fromActivity(
requireActivity(),
PhotoModuleDependencies::class.java
),
requireActivity().application
)
.inject(this)
The trick here is to get `EntryPointAccessors.fromActivity` instead of fromApplication.
You can check out [this link][1] if you wish to experiment yourself.
If you wish to add `ViewModel` to dynamic feature modules with hilt you can check out my answer [here][2].
[1]: https://github.com/SmartToolFactory/Dagger2-Tutorials/tree/master/Tutorial10-1DFM-DaggerHilt
[2]: https://stackoverflow.com/questions/63671489/how-to-create-viewmodel-in-dynamic-feature-module-with-dagger-hilt
I'm trying to create Espresso tests and using a mockWebServer the thing is when I try to create my mockWebServer it calls the real api call and I want to intercept it and mock the response.
My dagger organisation is :
My App
open class App : Application(), HasAndroidInjector {
lateinit var application: Application
#Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> = androidInjector
override fun onCreate() {
super.onCreate()
DaggerAppComponent.factory()
.create(this)
.inject(this)
this.application = this
}
}
Then MyAppComponent
#Singleton
#Component(
modules = [
AndroidInjectionModule::class,
AppModule::class,
RetrofitModule::class,
RoomModule::class,
AppFeaturesModule::class
]
)
interface AppComponent : AndroidInjector<App> {
#Component.Factory
interface Factory {
fun create(#BindsInstance application: App): AppComponent
}
}
Then I've created this TestApp
class TestApp : App() {
override fun androidInjector(): AndroidInjector<Any> = androidInjector
override fun onCreate() {
DaggerTestAppComponent.factory()
.create(this)
.inject(this)
}
}
And this is my TestAppComponent
#Singleton
#Component(
modules = [
AndroidInjectionModule::class,
AppModule::class,
TestRetrofitModule::class,
AppFeaturesModule::class,
RoomModule::class]
)
interface TestAppComponent : AppComponent {
#Component.Factory
interface Factory {
fun create(#BindsInstance application: App): TestAppComponent
}
}
Note: Here I've created a new module, called TestRetrofitModule where the BASE_URL is "http://localhost:8080", I don't know if I need something else.
Also I've created the TestRunner
class TestRunner : AndroidJUnitRunner() {
override fun newApplication(
cl: ClassLoader?,
className: String?,
context: Context?
): Application {
return super.newApplication(cl, TestApp::class.java.name, context)
}
}
And put it on the testInstrumentationRunner
Problem 1
I can not use
#Inject
lateinit var okHttpClient: OkHttpClient
because it says that it's not initialised.
Problem 2 (Solved thanks Skizo)
My mockWebServer is not dispatching the responses even-though is not pointing the real api call, is pointing the one that I've put to the TestRetrofitModule, the thing is that I have to link that mockWebServer and Retrofit.
The setup you posted looks correct. As for App not being provided, you probably need to bind it in your component, since right now you're binding TestApp only. So you need to replace
fun create(#BindsInstance application: TestApp): TestAppComponent
with
fun create(#BindsInstance application: App): TestAppComponent
I had the same problem with mockWebServer recently, what you need to do is to put a breakpoint and see what's the error, in my case I put it on my BaseRepository where I was doing the call, and found that the exception was :
java.net.UnknownServiceException: CLEARTEXT communication to localhost not permitted by network security policy
What I did to solve the problem is add this on my manifest.xml
android:usesCleartextTraffic="true"
But you may have to use other approaches you can take a look on android-8-cleartext-http-traffic-not-permitted.
When I try to do something similar, I don't create two types of application-components, just one. I provide them with different inputs, based on whether it's for the actual App or for the TestApp. No need for TestAppComponent at all. E.g.
open class App : Application(), HasAndroidInjector {
lateinit var application: Application
#Inject
lateinit var androidInjector: DispatchingAndroidInjector<Any>
override fun androidInjector(): AndroidInjector<Any> = androidInjector
override fun onCreate() {
super.onCreate()
DaggerAppComponent.factory()
.create(this, createRetrofitModule())
.inject(this)
this.application = this
}
protected fun createRetrofitModule() = RetrofitModule(BuildConfig.BASE_URL)
}
class TestApp : App() {
override fun createRetrofitModule() = RetrofitModule("http://localhost:8080")
}
#Module
class RetrofitModule(private val baseUrl: String) {
...
provide your Retrofit and OkHttpClients here and use the 'baseUrl'.
...
}
(not sure if this 'compiles' or not; I usually use the builder() pattern on a dagger-component, not the factory() pattern, but you get the idea).
The pattern here is to provide your app-component or its modules with inputs for the 'edge-of-the-world', stuff that needs to be configured differently based on the context in which the app would run (contexts such as build-flavors, app running on consumer device vs running in instrumentation mode, etc). Examples are BuildConfig values (such as base-urls for networking), interface-implementations to real or fake hardware, interfaces to 3rd party libs, etc.
How about a dagger module for your Test Class with a ContributeAndroidInjector in there and do Inject on a #Before method.
Your TestAppComponent:
#Component(modules = [AndroidInjectionModule::class, TestAppModule::class])
interface TestAppComponent {
fun inject(app: TestApp)
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: TestApp): Builder
fun build(): TestAppComponent
}
}
TestAppModule like:
#Module
interface TestAppModule {
#ContributesAndroidInjector(modules = [Provider::class])
fun activity(): MainActivity
#Module
object Provider {
#Provides
#JvmStatic
fun provideString(): String = "This is test."
}
// Your other dependencies here
}
And #Before method of Test Class you must be do:
#Before
fun setUp() {
val instrumentation = InstrumentationRegistry.getInstrumentation()
val app = instrumentation.targetContext.applicationContext as TestApp
DaggerTestAppComponent.builder().application(app).build().inject(app)
// Some things other
}
An important thing, you must be have (on build.gradle module app):
kaptAndroidTest "com.google.dagger:dagger-compiler:$version_dagger"
kaptAndroidTest "com.google.dagger:dagger-android-processor:$version"
Now, when you launch an Activity like MainActivity, Dagger will inject dependencies from your TestAppModule instead of AppModule before.
Moreover, If you want to #Inject to Test Class, you can add:
fun inject(testClass: TestClass) // On Your TestAppComponent
And then, you can call:
DaggerTestAppComponent.builder().application(app).build().inject(this) // This is on your TestClass
to Inject some dependencies to your TestClass.
Hope this can help you!!
I am presuming that you are trying to inject OkHttpClient:
#Inject
lateinit var okHttpClient: OkHttpClient
in your TestApp class, and it fails. In order to make it work, you will need to add an inject method in your TestAppComponent, to inject the overriden TestApp, so that it becomes:
#Singleton
#Component(
modules = [
AndroidInjectionModule::class,
AppModule::class,
TestRetrofitModule::class,
AppFeaturesModule::class,
RoomModule::class]
)
interface TestAppComponent : AppComponent {
#Component.Factory
interface Factory {
fun create(#BindsInstance application: App): TestAppComponent
}
fun inject(testApp: TestApp)
}
The reason why this is required, is because Dagger is type based, and uses the type of each class to be injected/provided to determine how to generate the code at compile-time. In your case, when you try to inject the TestApp, dagger will inject its superclass (the App class), because it only know that it has to inject the App class. If you have a look at the AndroidInjector interface (that you use in your AppComponent), you will see that it is declared like:
public interface AndroidInjector<T> {
void inject(T instance)
....
}
This means that it will generate a method:
fun inject(app App)
in the AppComponent. And this is why #Inject works in your App class, but does not work in your TestApp class, unless you explicitly provided it in the TestAppComponent.
I have two project modules (with this I mean two android modules with their own gradle, manifest, etc.. Not the Dagger module). I call them MyAppCore and MyApp. MyAppCore has the logic around the database access and network access. MyApp has all the UI (activities, views, modelviews, etc).
I'm using dagger 2 to inject dependencies of different components in my project, however, I'm having trouble to link both modules together.
MyApp and MyAppCore have their own AppComponent, where MyApp's provides the ViewModel factories and MyAppCore's provides the ones for database and network access (examples below).
I'm not sure how to link both AppComponent (or Applications) so that database and network accesses can be provided in MyApp. Here's what I have so far:
MyAppCore module
CoreApp
open class CoreApp : Application() {
val appComponent: AppComponent by lazy {
initializeComponent()
}
open fun initializeComponent(): AppComponent {
return DaggerAppComponent.builder()
.build()
}
}
AppComponent
#Singleton
#Component(modules = [AppModule::class])
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
}
AppModule
#Module
class AppModule {
#Singleton
#Provides
fun provideDb(app: Application) = MyDb.getInstance(app)
#Singleton
#Provides
fun provideCommentDao(db: MyDb) = db.commentDao()
}
CommentRep (to access the CommentDao)
#Singleton
class CommentRep #Inject constructor(private val dao: CommentDao) {
fun saveComment(comment: Comment){
dao.insert(comment)
}
}
MyAppCore also has the Room database implementation called MyDb and the interface CommentDao (I don't think I need to add this code in this question).
MyApp module
MyApp
open class MyApp : Application(), DaggerComponentProvider {
override val appComponent: AppComponent by lazy {
initializeComponent()
}
open fun initializeComponent(): AppComponent {
return DaggerAppComponent.builder()
.applicationContext(applicationContext)
.build()
}
}
DaggerComponentProvider
interface DaggerComponentProvider {
val appComponent: AppComponent
}
val Activity.injector get() = (application as DaggerComponentProvider).appComponent
AppComponent
#Singleton
#Component
interface AppComponent{
#Component.Builder
interface Builder {
#BindsInstance
fun applicationContext(applicationContext: Context): Builder
fun build(): AppComponent
}
fun commentsViewModelFactory(): ViewModelFactory<CommentsViewModel>
}
ViewModelFactory
class ViewModelFactory<VM : ViewModel> #Inject constructor(
private val viewModel: Provider<VM>
) : ViewModelProvider.Factory {
#Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>) = viewModel.get() as T
}
CommentsViewModel
class CommentsViewModel #Inject constructor(private val repository: CommentRep) : ViewModel() {
fun saveComment(comment: Comment){
repository.saveComment(comment)
}
}
And then my Activities which inject the VM but I don't think they are necessary to include their code in this question.
Of course, if I compile my project as this, the graph from MyAppCore is not generated and hence I get the error that I need to provide CommentDao because it's required by CommentRep which is used by CommentsViewModel. I guess MyAppCore application class is overridden by MyApp application class and hence MyAppCore's AppComponent is never instantiated and hence never added all the core's injections in my graph. How do I solve this problem? Thanks in advance!
Just use one component. First, add MyAppCore module to MyApp's gradle dependencies. Then, Let MyApp module provide the component which will include all the dagger modules in both project modules.
You could also change MyAppCore module to a library module since you only need one application module. In your build.gradle file, replace:
apply plugin: 'com.android.application'
to
apply plugin: 'com.android.library'
To add MyAppCore module to MyApp module's dependencies, add:
implementation project(":myappcore")
And for your component in MyApp module:
#Singleton
#Component(modules=[MyAppCoreModule::class, MyAppModule::class])
interface AppComponent {
...
}
So basically, you only need to provide modules in MyAppCore.
I have a list of Students which is displayed in RecyclerView and for each Student, I have StudentViewModel. As the StudentViewModel needs Student object which is retrieved runtime from database, I am not sure how can I setup constructor injection for StudentViewModel so I didn't attempt DI here. However, now I need another dependency in the viewmodel which can be resolved compile time and which is my NavUtil class.
I managed to get it injected in my StudentViewModel with following lines:
DaggerAppComponent.builder()
.application(MyApp.INSTANCE)
.build()
.inject(this)
But I don't think this is the correct way as I am referring Application class from my ViewModel just for the sake of DI. I read it might be possible with ViewModelFactory, but I am not able to find any solid example or reference to this. I am already using it for the ViewModels which has compile-time dependencies though, but not able to figure out the way for ViewModel(s) which has compile time and rumtime dependencies. Would be great if someone could point me in right direction.
BTW here's my overall implementation for DI:
App Component
#Component(modules = [AndroidInjectionModule::class, AndroidSupportInjectionModule::class,
AppModule::class, AppProvider::class,StudentProvider::class])
#Singleton
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(application: Application): Builder
fun build(): AppComponent
}
fun inject(app: MyApp)
fun inject(studentViewModel: StudentViewModel)
StudentProvider
#Module
abstract class StudentProvider {
#ContributesAndroidInjector(modules = [(ViewModelModule::class)])
abstract fun bindHomeActivity(): HomeActivity
}
ViewModelModules
#Module
class ViewModelModule {
#ActivityContext
#Provides
fun provideNavUtils(activity: Activity): NavUtil = NavUtil(activity)
}
StudentViewModel
class StudentViewModel(student: Student) : BaseViewModel() {
#Inject
lateinit var navUtils: NavUtil
init {
DaggerAppComponent.builder()
.application(MyApp.INSTANCE)
.build()
.inject(this)
}
fun onSettingsTapped() {
navUtils.navigateToSettings()
}
}
NavUtil
class NavUtil #Inject constructor(#ActivityContext private val context: Context) {
fun navigateToSettings() {
context.startActivity(Intent(context, SettingsActivity::class.java))
}
}
EDIT: It looks like activity context is not getting inject and instead, Application context is inject.
It is confusing that all web search results seem to use slightly different versions of Dagger or different approaches. I followed the example which claims that is the better "new way". (https://proandroiddev.com/exploring-the-new-dagger-android-module-9eb6075f1a46) The full sample source code is here (https://github.com/jshvarts/DaggerAndroidKotlinSampleApp).
Now, I want to know how a non-activity/fragment class could be provided with a Context. So, I added a simple class like this,
class Sample2 #Inject constructor (var app: Application)
{
fun print()
{
Log.d("sample2", app.packageName);
}
}
But even though the sample project had AppModule and AppComponent, the compilation failed, because app could not be provided.
I have searched the web and found this method (https://github.com/google/dagger/issues/832). I followed that code and modified the sample's AppModule and AppComponent like this,
#Module(includes = [AndroidInjectionModule::class])
abstract class AppModule {
#Binds
abstract fun application(app: App):Application;
#Singleton
#Provides
fun providesCommonHelloService() = CommonHelloService()
}
#Singleton
#Component(modules = [AndroidInjectionModule::class,
AppModule::class, ActivitiesModule::class])
interface AppComponent:AndroidInjector<App>
{
#Component.Builder
abstract class Builder:AndroidInjector.Builder<App>(){}
}
class App : Application(), HasActivityInjector {
#Inject
lateinit var activityInjector: DispatchingAndroidInjector<Activity>
override fun onCreate()
{
super.onCreate()
DaggerAppComponent.builder().create(this).inject(this)
}
override fun activityInjector(): AndroidInjector<Activity> = activityInjector
}
But the, I get the following compilation error.
AppModule.java:7: error: A #Module may not contain both non-static #Provides methods and abstract #Binds or #Multibinds declarations
public abstract class AppModule {
Again, as I have said in the beginning, the Dagger examples on the Internet are all slightly different, I do not know how to take two features from two examples.
It is better to separate #Binds and #Provides, you can create a component class:
#Singleton
#Component(
modules = [(AppModule::class)]
)
interface AppComponent {
#Component.Builder
interface Builder {
#BindsInstance
fun application(app: Application): Builder
fun build(): AppComponent
}
}
then an AppModule class for all your #Provides
#Module
class AppModule() {
#Singleton
#Provides
fun providesCommonHelloService() = CommonHelloService()
}