Test Driven Development(TDD) with Mockito Android
In Test driven development (TDD), unlike Behavior drive development (BDD) first we write a Test, run the test. Definitely first time it will fail, because we haven't written the code for which going to test, then according to our test we start writing code to pass these tests. same we repeats till all test pass. to do this with mockito, we need to add a dependency in your build.gradle file as normally we add other dependency
testImplementation "org.mockito:mockito-core:2.15.0"
Mockito is basically a Mocking library used for mocking objects, you can get more about from its official documentation here
I will explain this more by simple demo:
Login View
package com.hoppers.mockito.demo
interface ILoginView {
fun getUserName(): String
fun showUserNameError(showError: Int)
fun getPassword(): String
fun showPasswordError(showError: Int)
}
Presenter
Click alt+Enter from android studio, it will show a way to create test of this class
In next dialog select testing library (Junit 4) class name and check on appropriate method to generate automatically by android studio and choose the path of this test class in test folder of project. initially your test file will be something similar
Here @Before and @After annotation tells that these method will be executed before the test and at the end of the test and used to do kind of initialization thing and releasing the resources, it works bit similar like onCreate and onDestroy method of android activity. Now lets think about normal login flow using username and password. whats our requirement here:
- username
- password
if username is empty show Error and if password is empty show Error, Just go to test class and write test case to test these flow:
This is the first test that will check validation if username is empty
@Test
fun shouldShowErrorMessageWhenUserNameEmpty() {
}
Here we need to return “” whenever view.getUserName called and click on onLoginClick() and verify through mockito that showUserNameError() method should call
@Test
fun shouldShowErrorMessageWhenUserNameEmpty() {
WhenEver(view.getUserName()).thenReturn("")
presenter?.onLoginClick()
verify(view).showUserNameError(R.string.showUserNameError)
}
Now to run this code we need view, presenter object and presenter class is dependent on LoginService class, we will create these object through Mockito , we will press alt+enter and create a field and will annotate field with @Mock which tells mockito to give a mock (fake) object of these classes and mockito will take care
@Mock
private lateinit var view: ILoginView
private var presenter: Presenter? = null@Mock
private lateinit var service: LoginService
But here we need presenter object also and it is dependent on loginview and loginservice, no worry we already have mocked object of both , we can simply create presenter object with help of these, will do it in setUp method here and will annotate it with @Before
@Before
fun setUP() {
presenter = Presenter(view, service)
}
Our first test completed now, this is actual thing in TDD, but it will not work as we have written test only and not yet written actual code in our app, now lets do it
class LoginActivity : AppCompatActivity(), ILoginView {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_login)
}
override fun getPassword(): String {
return password.text.toString()
}
override fun showPasswordError(showError: Int) {
password.error = getString(showError)
}
private val presenter: Presenter by lazy {
Presenter(this, LoginService())
}
override fun getUserName(): String {
return email.text.toString()
}
override fun showUserNameError(showError: Int) {
email.error = getString(showError)
}
That’s our test and code both ready now, can we test this ? yes
go to test file and press ctrl+shift+f10, What happen , Error
org.mockito.exceptions.base.MockitoException:
Cannot mock/spy class com.hoppers.mockito.demo.LoginService
Mockito cannot mock/spy because :
— final class
As we know in Kotlin by default every class is final, and mockito unable to mock final class object… Problem, Solution is here
we need to create a file org.mockito.plugins.MockMaker in test/resources folder and add below text in the file
mock-maker-inline
now it will looks like :
Looks nice, can we test ? yes go to test file and press ctrl+shift+f10, Success here , now test passed.
This is simple basic TDD implementation in andorid using kotlin, Hopefully with all these you can get a basic idea behind TDD and Mockito
You can get full source code of this example here