목표 : viewModel 과 fragment 쌍 통합 테스트

  1. TasksViewModel 내부에서 생성했던 TasksRepository를 뷰모델 생성자에서 주입 받도록 변경
class TasksViewModel( private val tasksRepository: TasksRepository ) : ViewModel() { 
    // Rest of class 
}
  1. 기본 생성자가 아닌 다른 생성자를 가진 뷰모델은 Factory를 이용해 생성해야함
class TaskViewModelFactory(
    private val tasksRepository: TasksRepository
) : ViewModelProvider.NewInstanceFactory() {
    override fun <T : ViewModel> create(modelClass: Class<T>): T {
        return (TasksViewModel(tasksRepository) as T)
    }
}
  1. TasksFragment에서 팩토리를 이용해 TasksViewModel 생성
private val viewModel by viewModels<TasksViewModel> {
    TasksViewModelFactory(DefaultTasksRepository.getRepository(requireActivity().application))
}

TasksViewModel 에서 FakeTasksRepository 만들어서 테스트 하는 법

class TasksViewModelTest{

private lateinit var fakeTasksRepository: FakeTestRepository
private lateinit var tasksViewModel: TasksViewModel

@Before
    fun setUpViewModel() {
				1. FakeTasksRepository 생성
        fakeTasksRepository = FakeTestRepository()
        val task1 = Task("Title1", "Description1")
        val task2 = Task("Title2", "Description2", true)
        val task3 = Task("Title3", "Description3", true)
        tasksRepository.addTasks(task1, task2, task3)
        //There's no need to use the delegate property or a ViewModelProvider,
        // you can just directly construct the ViewModel in unit tests.
				2. FakeTasksRepository를 주입한 TasksViewModel 생성 
        tasksViewModel = TasksViewModel(fakeTasksRepository)
    }
}

FakeTasksRepository 만드는 법

  1. DefaultTasksRepository (원래 repository)에서 TaskRepository interface 추출
  2. DefaultTasksRepository 와 테스트용 FakeTestRepository 둘다 TaskRepository implementation하도록 설정

위에서 viewModel에 fakeRepository를 넣는것 까진 했다.

따라서 viewModel 로컬 테스트는 가능.

그런데 Fragment를 테스트 하려니까, fragment 내부에서 viewModel을 만들고 있었다.

fragment는 직접 생성하지 않기 때문에 fragment 생성자에 viewModel을 주입 받을 수 없다.

그래서 serviceLocator 이라는 것을 사용한다.

그러면, fragment 테스트 클래스를 만들어서, fakeRepository ( 혹은 fakeRepository를 생성자로 가지는 viewModel)을 만들 수 있다.