Espresso IdlingResource example in kotlin and coroutine doesn't work

Viewed 793

Basically I wanna create an example which is the same to android/testing-samples, except using kotlin and coroutine.

The SimpleIdlingResource.kt would look like

class SimpleIdlingResource : IdlingResource {
    @Nullable
    @Volatile
    private var mCallback: IdlingResource.ResourceCallback? = null

    private val mIsIdleNow = AtomicBoolean(true)

    override fun getName(): String {
        return this.javaClass.name
    }

    override fun isIdleNow(): Boolean {
        return mIsIdleNow.get()
    }

    override fun registerIdleTransitionCallback(callback: IdlingResource.ResourceCallback) {
        mCallback = callback
    }

    fun setIdleState(isIdleNow: Boolean) {
        mIsIdleNow.set(isIdleNow)
        if (isIdleNow && mCallback != null) {
            mCallback!!.onTransitionToIdle()
        }
    }
}

Android Studio converted the Java code for me, and I just fixed some syntax errors.

MainActivity.kt would looks like:

class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding

    @Nullable
    private var mIdlingResource: SimpleIdlingResource? = null

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)

        binding = ActivityMainBinding.inflate(layoutInflater)
        val view = binding.root
        setContentView(view)

        binding.changeTextBt.setOnClickListener {
            mIdlingResource?.setIdleState(false)

            val newText = binding.editTextUserInput.text
            GlobalScope.launch {
                delay(1000L)
                withContext(Dispatchers.Main) {
                    binding.textToBeChanged.text = newText
                    mIdlingResource?.setIdleState(true)
                }
            }
        }
    }

    @VisibleForTesting
    fun getIdlingResource(): IdlingResource {
        if (mIdlingResource == null) {
            mIdlingResource = SimpleIdlingResource()
        }
        return mIdlingResource as SimpleIdlingResource
    }
}

I use Viewbinding to extract the elements on the main app, and use a simple coroutine to simulate the delay.

MainActivityTest.kt looks like:

@RunWith(AndroidJUnit4::class)
class MainActivityTest {
    private var mIdlingResource: IdlingResource? = null

    @Before
    fun registerIdlingResource() {
        val activityScenario = ActivityScenario.launch(MainActivity::class.java)

        activityScenario.onActivity{ activity ->
            mIdlingResource = activity.getIdlingResource()
            // To prove that the test fails, omit this call:
            IdlingRegistry.getInstance().register(mIdlingResource)
        }
    }

    @Test
    fun whenChangeButtonIsPressedAndTextViewIsCorrect() {
        ActivityScenario.launch(MainActivity::class.java)
        val text2test = "cool!"
        onView(withId(R.id.editTextUserInput))
            .perform(typeText(text2test))

        onView(withId(R.id.changeTextBt))
            .perform(click())

        onView(withId(R.id.textToBeChanged))
            .check(matches(withText(text2test)))
    }

    @After
    fun unregisterIdlingResource() {
        if (mIdlingResource != null) {
            IdlingRegistry.getInstance().unregister(mIdlingResource)
        }
    }
}

Once again, Android Studio converted the register and unregister part for me, when I tried to run the test cases, there's an error as follows:

Expected: with text: is "cool!"

Got: ... text=yo world

If I remove the coroutine part from the main app as well the IdlingResource part, the test case works.

Not sure if there's anything that I missed?

0 Answers
Related