1 回答

TA贡献1820条经验 获得超10个赞
从EpicPandaForce 的回答和一些研究(见这篇文章)中得到启发后,我找到了一个我很满意的解决方案。
我决定从我的项目中删除 Dagger 2,因为我对它进行了过度设计。我的应用程序依赖于存储库类和现在的ViewModelProvider.Factory实现,一旦应用程序运行,这两者都是必需的。我对 Dagger 的了解已经足够让我自己满意了,所以我很乐意将它从这个特定的项目中移除并在一个Application类中创建两个依赖项。这些类如下所示:
我的应用程序类创建了我的ViewModel工厂,为它提供了存储库,getViewModelFactory()并向我的活动公开了一个方法:
public class JourneyStoreApplication extends Application {
private final JourneyStoreViewModelFactory journeyStoreViewModelFactory;
{
// Instantiate my viewmodel factory with my repo here
final JourneyRepository journeyRepository = new JourneyRepositoryImpl();
journeyStoreViewModelFactory = new JourneyStoreViewModelFactory(journeyRepository);
}
@Override
public void onCreate() {
super.onCreate();
}
public JourneyStoreViewModelFactory getViewModelFactory(){
return journeyStoreViewModelFactory;
}
}
我的ViewModel工厂,它使用存储库引用创建新ViewModel的 s。随着我添加更多Activity类和ViewModels,我将对此进行扩展:
public class JourneyStoreViewModelFactory implements ViewModelProvider.Factory {
private final JourneyRepository journeyRepository;
JourneyStoreViewModelFactory(JourneyRepository journeyRepository){
this.journeyRepository = journeyRepository;
}
@NonNull
@Override
public <T extends ViewModel> T create(@NonNull Class<T> modelClass) {
if(modelClass == AddJourneyViewModel.class){
// Instantiates the ViewModels with their repository reference.
return (T) new AddJourneyViewModelImpl(journeyRepository);
}
throw new IllegalArgumentException(String.format("Requested class %s did not match expected class %s.", modelClass, AddJourneyViewModel.class));
}
}
我的AddJourneyActivity班级,它使用AddJourneyViewModel:
public class AddJourneyActivity extends AppCompatActivity {
private static final String TAG = AddJourneyActivity.class.getSimpleName();
private AddJourneyViewModel addJourneyViewModel;
private EditText departureTextField;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_add_journey);
JourneyStoreApplication app = (JourneyStoreApplication) getApplication();
addJourneyViewModel = ViewModelProviders
// Gets the ViewModelFactory instance and creates the ViewModel.
.of(this, app.getViewModelFactory())
.get(AddJourneyViewModel.class);
departureTextField = findViewById(R.id.addjourney_departure_addr_txt);
}
//...
}
但这仍然留下了测试的问题,这是我的主要问题之一。旁注:我将所有ViewModel类都抽象化(仅使用方法),然后为我的真实应用程序和测试代码实现它们。这是因为我发现它比直接extending my ViewModels 更容易,然后尝试覆盖他们的方法并隐藏他们的状态以创建一个假版本。
无论如何,我扩展了我的JourneyStoreApplication课程(与我知道的自己相矛盾,但它是一个小课程,所以很容易管理)并用它来创建一个提供我的假ViewModels 的地方:
public class FakeJourneyStoreApplication extends JourneyStoreApplication {
private final JourneyStoreViewModelFactory fakeJourneyStoreViewModelFactory;
{ // Create my fake instances here for my tests
final JourneyRepository fakeJourneyRepository = new FakeJourneyRepositoryImpl();
fakeJourneyStoreViewModelFactory = new FakeJourneyStoreViewModelFactory(fakeJourneyRepository);
}
@Override
public void onCreate() {
super.onCreate();
}
public JourneyStoreViewModelFactory getViewModelFactory(){
return fakeJourneyStoreViewModelFactory;
}
}
我制作了我ViewModel的 s 的假实现,并从FakeJourneyStoreViewModelFactory. 稍后我可能会简化这一点,因为“假”样板可能比需要的要多。
离开本指南(第 4.9 节),我扩展为我的测试AndroidJUnitRunner提供我的假货: Application
public class CustomTestRunner extends AndroidJUnitRunner {
@Override
public Application newApplication(ClassLoader cl, String className, Context context)
throws ClassNotFoundException, IllegalAccessException, InstantiationException {
return super.newApplication(cl, FakeJourneyStoreApplication.class.getName(), context);
}
}
最后,我将自定义测试运行器添加到我的build.gradle文件中:
android {
defaultConfig {
// Espresso
testInstrumentationRunner "com.<my_package>.journeystore.CustomTestRunner"
}
}
我将把这个问题再开放 24 小时,以防有人要添加有用的东西,然后我会选择这个作为答案。
添加回答
举报