我是Android单元测试的新手,并通过了一些教程来熟悉mockito和robolectric。
我的应用正在使用Dagger 2将我的EventService
注入我的MainActivity
中。对于我的MainActivityUnitTest
,我设置了一个TestServicesModule
以提供EventService
的模拟版本,以便可以使用Robolectric对我的MainActivity
进行单元测试。
我在让ServiceCallback
上的EventService.getAllEvents(callback: ServiceCallback)
在单元测试中执行时遇到问题。我在@Setup
类的MainActivityUnitTest
中验证了EventService
被作为模拟对象注入。我看了几本教程和博客文章,据我所知,我做的一切正确。 refreshData()
中的MainActivity
函数已成功调用,我可以看到对eventsService.getAllEvents(callback)
的调用正在执行。但是doAnswer {}
lambda函数永远不会执行。
这是我的相关代码:
AppComponent.kt
@Singleton
@Component(modules = [
AppModule::class,
ServicesModule::class,
FirebaseModule::class
])
interface AppComponent {
fun inject(target: MainActivity)
}
ServicesModule.kt
@Module
open class ServicesModule {
@Provides
@Singleton
open fun provideEventService(db: FirebaseFirestore): EventsService {
return EventsServiceImpl(db)
}
}
EventsService.kt
interface EventsService {
fun getAllEvents(callback: ServiceCallback<List<Event>>)
fun getEvent(id: String, callback: ServiceCallback<Event?>)
}
MainActivity.kt
class MainActivity : AppCompatActivity() {
@Inject lateinit var eventsService: EventsService
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
(application as App).appComponent.inject(this)
...
}
override fun onStart() {
super.onStart()
refreshData()
}
eventsService.getAllEvents(object: ServiceCallback<List<Event>> {
override fun onCompletion(result: List<Event>) {
viewModel.allEvents.value = result
loading_progress.hide()
}
})
}
现在我们开始测试:
TestAppComponent.kt
@Singleton
@Component(modules = [
TestServicesModule::class
])
interface TestAppComponent : AppComponent {
fun inject(target: MainActivityUnitTest)
}
TestServicesModule.kt
@Module
class TestServicesModule {
@Provides
@Singleton
fun provideEventsService(): EventsService {
return mock()
}
}
MainActivityUnitTest.kt
@RunWith(RobolectricTestRunner::class)
@Config(application = TestApp::class)
class MainActivityUnitTest {
@Inject lateinit var eventsService: EventsService
@Before
fun setup() {
val testComponent = DaggerTestAppComponent.builder().build()
testComponent.inject(this)
}
@Test
fun givenActivityStarted_whenLoadFailed_shouldDisplayNoEventsMessage() {
val events = ArrayList<Event>()
doAnswer {
//this block is never hit during debug
val callback: ServiceCallback<List<Event>> = it.getArgument(0)
callback.onCompletion(events)
}.whenever(eventsService).getAllEvents(any())
val activity = Robolectric.buildActivity(MainActivity::class.java).create().start().visible().get()
val noEventsView = activity.findViewById(R.id.no_events) as View
//this always evaluates to null because the callback is never set from the doAnswer lambda
assertThat(callback).isNotNull()
verify(callback)!!.onCompletion(events)
assertThat(noEventsView.visibility).isEqualTo(View.VISIBLE)
}
}
编辑:添加应用程序和TestApp
open class App : Application() {
private val TAG = this::class.qualifiedName
lateinit var appComponent: AppComponent
override fun onCreate() {
super.onCreate()
appComponent = initDagger(this)
}
open fun initDagger(app: App): AppComponent {
return DaggerAppComponent.builder().appModule(AppModule(app)).build()
}
}
class TestApp : App() {
override fun initDagger(app: App): AppComponent {
return DaggerTestAppComponent.builder().build()
}
}