I can't change project code, I can only write tests.
I have a function for testing:
fun funToBeTested() {
ClasWithWorkManager().veryVeryBadFunc(TAG)
// a lot of code to be tested below
...
}
and class with WorkManager:
class ClasWithWorkManager() {
companion object {
#JvmStatic
fun veryVeryBadFunc(tag: String) {
WorkManager.getInstance().cancelAllWorkByTag(tag)
WorkManager.getInstance().pruneWork()
}
}
}
There are no Android class references in the rest of this func.
Can I somehow cover with Unit test all funToBeTested() except of its first line?
Right now I have obvious WorkManager is not initialized properly. problem
Related
I created a validation use case in which I'm validating the input using isDigitsOnly that use TextUtils internally.
override fun isDigitsOnly(size: String): Boolean {
return !size.trim().isDigitsOnly()
}
when I tried to test it, I got this error
Method isDigitsOnly in android.text.TextUtils not mocked
Does anyone know how I can mock the textUtils in my test class
#RunWith(MockitoJUnitRunner::class)
class ValidationInputImplTest {
#Mock
private lateinit var mMockTextUtils: TextUtils
private lateinit var validationInputImpl: ValidationInputImpl
#Before
fun setUp() {
validationInputImpl = ValidationInputImpl()
}
#Test
fun `contains only digits, returns success`() {
val input = "66"
val result = validationInputImpl(input)
assertTrue(result is ValidationResult.Success)
}
}
At the time of writing the answer,you cannot do that. Because the android code ,that you see is not actual code. You cannot create unit test for that. The default implementation of the methods in android.jar is to throw exception.
One thing you can do is, adding the below in build.gradle file.
But it make the android classes not to throw exception. But it will always return default value. So the test result may actually not work. It is strictly not recommended.
android {
testOptions {
unitTests.returnDefaultValues = true
}
}
The better way to do copy the code from android source and paste the file under src/test/java folder with package name as android.text .
Link to Answer
Maybe this is very basic question but could not find anything online.
I have created a object class in kotlin contains few methods. I am calling those from ViewModel and I have written junit test case for ViewModel where object class instance is mocked, fine so far.
Now, I want to write junit for my object class separately as well even though from ViewModel verify() calls are working fine.
Some code snippet from my project
object InfoHelper {
fun method(param: Xyz): Boolean {
return when(param) {
Result.OK -> true
else -> false
}
}
}
Unit testing Kotlin object classes:
The same as testing a Java static method and class. The class under test and it's methods can be tested directly without initialisation.
Using your class as a loose example..
object InfoHelper {
fun method(param: String): Boolean {
return when(param) {
"my string" -> true
else -> false
}
}
}
The test:
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
class InfoHelperTest {
#Test
fun `some test returns true`() {
assertTrue(InfoHelper.method("my string"))
}
#Test
fun `some test returns false`() {
assertFalse(InfoHelper.method("not my string"))
}
}
I am working on an Android library and I am writing an instrumented test for it using UI Automator and Mockk.
The library has a class called InstallManager which will install stuff on the device. I want the InstallManager to throw an exception so that I can test if an error notification will be shown.
All I do is finding the Update (Install) button and click on it
val updateButtonComponent = device.findObject(By.text(updateButtonText))
updateButtonComponent.click()
How can I mock/manipulate the InstallManager which is being used by the library during the automated test?
What I tried:
I tried mocking the InstallManager before running the automated test, hoping that UI Automator would magically know that it should use this mocked InstallManager. But (as I thought already) it does not work like that...
private fun breakInstallManager() {
installManager = spyk(InstallManager(mockk(relaxed = true), nonExistentFile))
every { installManager.getString(any()) } returns ""
every { installManager.packageName } returns ""
}
For mocking InstallManager class in android tests, call MockKAnnotations.init method. Then in the test method you can specify the return value
#RelaxedMockK
private lateinit var installManager: InstallManager
#Before
fun setUp() {
MockKAnnotations.init(this)
// …
}
#Test
fun installManagerTest(){
every { installManager.getString(any()) } returns ""
every { installManager.packageName } returns ""
// …
}
I have an object in kotlin that controls the current user's session information. I want to mock the sign in method which has a call back.
While testing, I need to mock this method in the SessionController object.
object SessionController {
...
fun signIn(username: String, password: String, signInCallBack: SignInCallBack) {
sessionApi.attemptSignIn(username,password,object: SignInCallBack{
override fun onSignInComplete() {
signInCallBack.onSignInComplete()
}
override fun onErrorOccurred(errorCode: Int, errorMessage: String) {
signInCallBack.onErrorOccurred(errorCode)
}
})
}
....
}
The AndroidTest goes something like this:
#RunWith(AndroidJUnit4::class)
class LoginActivityTest {
#Test
fun loginErrorShowing() {
test.tapUsernameField()
test.inputTextinUsernameField("wrongusername")
test.pressUsernameFieldIMEAction()
test.inputTextinPasswordField("randomPassword")
test.pressPasswordFieldIMEAction()
Espresso.onView(ViewMatchers.withId(R.id.errorText)).check(ViewAssertions.matches(withText("Wrong Password")))
}
}
Any suggestions/ideas as to how I can achieve this? I've read online to use Mockk for kotlin but have't been able to mock this method and invoke the appropriate callback. Any suggestions on improving the structure would also be appreciated.
Thanks
Well in my opinion you should made SessionController implementing an interface.
object SessionController: ISessionController {
override fun signIn(username: String, password: String, signInCallBack: SignInCallBack) {
(...)
}
}
interface ISessionController {
fun fun signIn(username: String, password: String, signInCallBack: SignInCallBack)
}
This will give you a lot of possibilities to solve your problem like:
Dependency Injection
Test product flavour
Simple mockk() cration in your test code
It is a bit hard to give you very strict answer because you didn't post any UT code ;)
EDIT
It is hard to cover such a big topic as mocking in one post ;)
Here are some great articles:
Dependency Injection: https://medium.com/#elye.project/fast-mocked-ui-tests-on-android-kotlin-89ed0a8a351a
Using different flavour for tests: https://android-developers.googleblog.com/2015/12/leveraging-product-flavors-in-android.html
Creating Unit Tests you can always do simple:
presenter.sth = mockk<ISessionController>()
I am writing an App for Android, and I am wanting to start writing tests for the classes I am writing. I am fairly new to writing test cases.
Right now to create a test, I use IntelliJ and use it's wizard to make a new JUnit4 test. The wizard allows me to select methods from my class to test.
But for the object I am testing, I do not want a negative number passed to the constructor.
class MinuteTime(private val minutes : Int) {
init {
if (minutes < 0) {
throw IllegalArgumentException("Cannot be less than 0.")
}
}
...
Where in my Test class is the best place to test these constraints? I know that to test the constraints, I just need to make sure the exception is thrown and caught, but I am unsure if I should make a new method for this, or just wedge it into one of the functions IntelliJ pre-made for me. Here is the generated test class:
class MinuteTimeTest {
#Test
fun getTimeInMinutes() {
}
#Test
fun getHours() {
}
#Test
fun getMinutes() {
}
#Test
fun plus() {
}
}
I'd definetly recommend to wrap this into a separate test method. Its concern is simply testing the validation during initialization:
#Test
fun negativeNumberConstructorTest() {
assertFailsWith(IllegalArgumentException::class){
MinuteTime(-1)
}
}
It’s using kotlintest on top of JUnit