2016-06-30 40 views
2

我正在学习使用Mockito和Robolectric在Android上进行测试。我用RxJava和Dagger2在Kotlin上使用Clean Architecture创建了一个非常简单的应用程序。设备上的所有设备都能正常工作,但我无法通过测试。这里是我的LoginPresenterTest:测试Android Kotlin应用程序 - Migito with Dagger注入null

@RunWith(RobolectricGradleTestRunner::class) 
@Config(constants = BuildConfig::class) 
public class LoginPresenterTest { 

    private lateinit var loginPresenter: LoginPresenter 

    @Rule @JvmField 
    public val mockitoRule: MockitoRule = MockitoJUnit.rule() 

    @Mock 
    private lateinit var mockContext: Context 

    @Mock 
    private lateinit var mockLoginUseCase: LoginUseCase 

    @Mock 
    private lateinit var mockLoginView: LoginView 

    @Mock 
    private lateinit var mockCredentialsUseCase: GetCredentials 

    @Before 
    public fun setUp() { 
     loginPresenter = LoginPresenter(mockCredentialsUseCase, mockLoginUseCase) 
     loginPresenter.view = mockLoginView 
    } 

    @Test 
    public fun testLoginPresenterResume(){ 
     given(mockLoginView.context()).willReturn(mockContext) 
     loginPresenter.resume(); 
    } 
} 

LoginPresenter构造器:

class LoginPresenter @Inject constructor(@Named("getCredentials") val getCredentials: UseCase, 
            @Named("loginUseCase") val loginUseCase: LoginUseCase) : Presenter<LoginView> 

loginPresenter.resume()我有:

override fun resume() { 
    getCredentials.execute(GetCredentialsSubscriber() as DefaultSubscriber<in Any>) 
} 

最后,GetCredentials:

open class GetCredentials @Inject constructor(var userRepository: UserRepository, 
            threadExecutor: Executor, 
            postExecutionThread: PostExecutionThread): 
            UseCase(threadExecutor, postExecutionThread) { 

    override fun buildUseCaseObservable(): Observable<Credentials> = userRepository.credentials() 

} 

ŧ他的问题是,GetCredentials中的每个字段都是空的。我想我错过了一些东西(我从这个项目中拿出了模式:https://github.com/android10/Android-CleanArchitecture),但我找不到它是什么。有谁知道可能会导致这种情况?

回答

1

您使用的模拟实例为GetCredentials@Mock var mockCredentialsUseCase: GetCredentials),这就是为什么您的null s在其领域。嘲讽所有与被测试的主要类别不同的​​东西(LoginPresenter)并不是一个好主意。想到这一点的一种方法是将依赖关系划分为peers and internals。我会重写测试类似于:

inline fun <reified T:Any> mock() : T = Mockito.mock(T::class.java) 

@RunWith(RobolectricGradleTestRunner::class) 
@Config(constants = BuildConfig::class) 
public class LoginPresenterTest { 

    val mockContext:Context = mock() 
    val mockLoginView:LoginView = mock().apply { 
     given(this.context()).willReturn(mockContext) 
    } 
    val userRepository:UserRepository = mock() // or some in memory implementation 
    val credentials = GetCredentials(userRepository, testThreadExecutor, testPostThreadExecutor) // yes, let's use real GetCredentials implementation 
    val loginUseCase = LoginUseCase() // and a real LoginUseCase if possible 
    val loginPresenter = LoginPresenter(credentials, loginUseCase).apply { 
     view = mockLoginView 
    } 

    @Test 
    public fun testLoginPresenterResume(){ 
     given(mockLoginView.context()).willReturn(mockContext) 
     loginPresenter.resume(); 

     // do actual assertions as what should happen 
    } 
} 

像往常一样,你需要考虑你正在测试的东西。测试的范围不一定限于一个班级。考虑你正在测试的功能而不是类(比如在BDD中)往往更容易。最重要的是尽量避免像this这样的测试 - 在我看来,这种测试在回归测试中增加了很小的价值,但仍然阻碍了重构。

PS。 Roboelectric add helper functions for context

+0

谢谢你的回复。我通过创建'UseCaseTestClass'解决了这个问题,它嘲笑'GetCredential'行为,所以一切正常。 –