5

テストできるように、ViewModel をテストに挿入する方法をかなり探していました。ビューモデルに、いくつかのビジネス ロジック インタラクターを含むコンストラクター インジェクションがあるとします。フラグメントに簡単に挿入できますが、テストでは成功しません。

@HiltAndroidTest
class ViewModelTest

 val randomViewmodel: RandomViewmodel// now what ? since by viewModels() is not accessible in tests

    @Test
    fun viewModelTet() {
        randomViewmodel.triggerAction()
        assertEquals(RandomVIewState(1), randomViewmodel.getState())
    }

テストクラスに byViewModels() を実装しようとしましたが、コンストラクター引数なしでビューモデルを注入できましたが、成功しませんでした。

class RandomViewmodel @ViewModelInject constructor(
     private val randomInteractor: RandomInteractor
) : ViewModel
Caused by: java.lang.InstantiationException: class app.RandomViewModel has no zero argument constructor

理由: viewModel がインタラクターなどの依存関係を処理するため、画面ロジックを完全にテストできるようにしたいと考えています。さまざまなデータが流れている背後にかなりの数のロジックが存在する可能性があります。フラグメントのテストはおそらく可能ですが、多くのテストを伴う大規模なプロジェクトでは遅くなります。

私はすでにhttps://developer.android.com/jetpack/guide#test-componentsを読んでいます.画面全体のロジック

4

1 に答える 1

6

アノテーションは、他の@HiltViewModel方法で記述したバインディング モジュールを生成します。

それらの 1 つはBindsModuleと呼ばれるモジュールです。このクラスは、そのマルチバインディング モジュールとキー用のモジュールを含むラッパー クラス内で宣言されます。

たとえば、次の ViewModel を作成したとします。MyViewModel

package com.mypackage

@HiltViewModel
class MyViewModel @Inject constructor(
    private val someDependency: MyType
) : ViewModel()

次に、生成されたモジュールは次のようになります。

@OriginatingElement(
    topLevelClass = MyViewModel.class
)
public final class MyViewModel_HiltModules {
  private MyViewModel_HiltModules() {
  }

  @Module
  @InstallIn(ViewModelComponent.class)
  public abstract static class BindsModule {
    private BindsModule() {
    }

    @Binds
    @IntoMap
    @StringKey("com.mypackage.MyViewModel")
    @HiltViewModelMap
    public abstract ViewModel binds(MyViewModel vm);
  }

  @Module
  @InstallIn(ActivityRetainedComponent.class)
  public static final class KeyModule {
    private KeyModule() {
    }

    @Provides
    @IntoSet
    @HiltViewModelMap.KeySet
    public static String provide() {
      return "com.mypackage.MyViewModel";
    }
  }
}

したがって、ViewModel は、実装タイプに一致するテスト クラスのプロパティ@Bindsの注釈を使用するだけで、そのコントラクトを置き換えることができます。@BindValueこの場合は になりますMyViewModel

ViewModel に関連するモジュールをアンインストールする必要はありません。

@HiltAndroidTest
class MyFragmentInstrumentedUnitTest {
    @get:Rule val hiltRule = HiltAndroidRule(this)

    // either a subclass or a mock, as long as the types match
    // it will provide this instance as the implementation of the abstract binding 
    // `public abstract ViewModel binds(MyViewModel vm);`
    @BindValue
    val mockMyViewModel= mock<MyViewModel>()

    @Before
    fun init() {
        hiltRule.inject()
    }
}
于 2021-04-30T16:34:11.540 に答える