首页 > 解决方案 > Android 集成测试:使用 Dagger 和 Mockito 在活动中模拟逻辑/方法,并在测试中获取返回值

问题描述

我正在使用 Kotlin 开发一个 Android 应用程序。我还在使用 Dagger 和 Expresso 为我的应用程序编写集成测试。我现在在模拟逻辑时遇到问题。首先,让我向您展示如何使用 Dagger 在代码中模拟逻辑以进行集成测试。

我有用于测试的 Dagger 应用程序组件类,定义如下

@Singleton
@Component(modules = [ TestAppModule::class ])
interface TestAppComponent : AppComponent //App component is the actual class used for the application
{
    fun inject(app: MainActivity)
}

这是 TestAppModule 类的定义

@Module
open class TestAppModule (private val app: Application) {
    @Singleton
    @Provides
    open fun fileIOService(): IFileIOService {
        return FakeFileIOService()
    }
}

我还有一个名为 AppModule 的类,用于具有以下定义的实际应用程序代码。

@Module
open class TestAppModule (private val app: Application) {
    @Singleton
    @Provides
    open fun fileIOService(): IFileIOService {
        return FakeFileIOService()
    }
}

这个想法是集成测试将使用 TestAppModule,因此将注入 FakeFileIOService 类。对于实际应用程序,它将使用 AppModule,因此将注入 FileIOService 类。FakeFileIOService 类和 FileIOService 类都将从 IFileIOService 接口继承。IFileIOService 接口将具有以下定义。

interface IFileIOService
{
    fun saveFile(data: String)
}

FileIOService 类和 FakeIOService 类将有自己的 saveFile 方法实现版本。FakeIOService 将具有模拟版本。

我将在 MainActivity 类中为 IFileIOService 提供一个属性,用于依赖注入。

class MainActivity: AppCompatActivity()
{
    @Inject
    lateinit var fileIOService: IFileIOService
}

正如我所提到的,将注入 FakeFileIOService 类用于集成测试。代码工作正常。它使用伪造版本进行集成测试,使用具体版本进行实际应用。

但是现在,我遇到了一个问题,我需要使用 Mockito 模拟方法的逻辑并在测试中获取返回值。

但是,现在我在使用 Mokito 模拟逻辑来测试 File 并在测试中取回模拟值时遇到了问题。

以下是我的实现

fun saveFile(data: String) {
    FileOutputStream mockFos = Mockito.mock(FileOutputStream.class);
    mockFos.write(data.getBytes());
    mockFos.close();
}

从字面上看,我正在尝试使用 Mockito 模拟文件逻辑。然后我正在尝试编写一个类似这样的集成测试。

@get:Rule
var mainActivityRule: ActivityTestRule<MainActivity> = ActivityTestRule<MainActivity>(CameraActivity::class.java, true, false)

@Test
fun fileIsSaveInWhenButtonIsClicked() {
    Intents.init()
    var targetContext: Context = InstrumentationRegistry.getInstrumentation().targetContext
    var intent: Intent = Intent(targetContext, MainActivity::class.java)
    this.mainActivityRule.launchActivity(null) 
    onView(withId(R.id.button_save_file)).perform(click())

    //here I want to assert if the file is saved using Mockito something like this
    //verify(mockFos).write(data.getBytes()); the issue is that I cannot get the mockFos instance creatd in the saveFile method of the FakeFileIOService class
    Intents.release()
}

请参阅测试中的评论。问题是我想验证文件是否使用 Mockito 保存。但问题是我无法获取在 FakeIOService 类的 saveFile 中创建的 mockFos 实例。我该如何测试它?测试这种情况的最佳方法是什么?

标签: androidmockitointegration-testingdagger-2dagger

解决方案


您不应该模拟系统逻辑。写入文件并关闭文件是系统逻辑。你只应该嘲笑你自己的逻辑。

您应该验证的是是否调用了 saveFile 方法。并不是调用了 saveMyFile 的内容。

val mock = mock(IFileIOService::class.java)
mainActivity.fileIOService = mock

//do something that in return does fileIOService.saveFile

verify(mock).saveFile(any())

另一种选择是监视:

 val spy = spy(mainActivity.fileIOService)
 //do something that in return does fileIOService.saveFile

 verify(spy).saveFile(any())

推荐阅读