{"id":55700,"date":"2022-12-23T16:09:12","date_gmt":"2022-12-23T10:39:12","guid":{"rendered":"https:\/\/www.tothenew.com\/blog\/?p=55700"},"modified":"2024-01-02T17:42:04","modified_gmt":"2024-01-02T12:12:04","slug":"instrumental-testing-on-mlkit-integration-test","status":"publish","type":"post","link":"https:\/\/www.tothenew.com\/blog\/instrumental-testing-on-mlkit-integration-test\/","title":{"rendered":"Instrumental Testing on MLKit (integration test)"},"content":{"rendered":"<div class=\"dj dk dl dm dn l\">\n<div class=\"ab cl\">\n<div class=\"do bf dp dq dr ds\">\n<article>\n<div class=\"l\">\n<div class=\"l\">\n<section>\n<div class=\"gq gr gs gt gu\">\n<div class=\"\">\n<h1 id=\"6014\" class=\"pw-post-title gv gw gx bd gy gz ha hb hc hd he hf hg hh hi hj hk hl hm hn ho hp hq hr hs ht bi\" data-selectable-paragraph=\"\">Introduction<\/h1>\n<\/div>\n<p id=\"1f2d\" class=\"pw-post-body-paragraph hu hv gx hw b hx jq hz ia ib jr id ie if js ih ii ij jt il im in ju ip iq ir gq bi\" data-selectable-paragraph=\"\">Instrumented tests run on Android devices, whether physical or emulated. As such, they can take advantage of the Android framework APIs. Instrumented tests, therefore, provide more fidelity than local tests, though they run much more slowly.<\/p>\n<figure class=\"jw jx jy jz ek ka dy dz paragraph-image\">\n<div class=\"kb kc di kd bf ke\" role=\"button\">\n<div class=\"dy dz jv\"><img decoding=\"async\" loading=\"lazy\" class=\"bf kf kg c\" role=\"presentation\" src=\"\/blog\/wp-ttn-blog\/uploads\/2024\/01\/0-sQDV2ZVOeZVoWwG.png\" alt=\"\" width=\"700\" height=\"522\" \/><\/div>\n<\/div><figcaption class=\"kh ki ea dy dz kj kk bd b be z fs\" data-selectable-paragraph=\"\">* Image from\u00a0<a class=\"ae kl\" href=\"https:\/\/developer.android.com\/training\/testing\/fundamentals\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/developer.android.com\/training\/testing\/fundamentals<\/a><\/figcaption><\/figure>\n<p id=\"6fca\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\"><strong class=\"hw gy\">Set up your testing environment<\/strong><\/p>\n<p id=\"2b85\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">In your app\u2019s top-level build.gradle file, you need to specify these libraries as dependencies:<\/p>\n<pre class=\"jw jx jy jz ek km kn ko bn kp kq bi\"><span id=\"3fec\" class=\"kr it gx kn b be ks kt l ku kv\" data-selectable-paragraph=\"\">android {\r\ndefaultConfig {\r\n testInstrumentationRunner <span class=\"hljs-string\">\"androidx.test.runner.AndroidJUnitRunner\"<\/span>\r\n }\r\n}\r\n\r\ndependencies {\r\n androidTestImplementation \u201candroid.test:runner:<span class=\"hljs-variable\">$androidXTestVersion<\/span>\u201d\r\n androidTestImplementation \u201candroidx.test:rules:<span class=\"hljs-variable\">$androidXTestVersion<\/span>\u201d\r\n}<\/span><\/pre>\n<h1 id=\"5edf\" class=\"is it gx bd iu iv iw ix iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp bi\" data-selectable-paragraph=\"\">Set up your Folders (test directories)<\/h1>\n<p id=\"4056\" class=\"pw-post-body-paragraph hu hv gx hw b hx jq hz ia ib jr id ie if js ih ii ij jt il im in ju ip iq ir gq bi\" data-selectable-paragraph=\"\">A typical project in Android Studio contains two directories that hold tests depending on their execution environment. Organize your tests in the following directories as described:<\/p>\n<ul class=\"\">\n<li id=\"ec28\" class=\"kw kx gx hw b hx hy ib ic if ky ij kz in la ir lb lc ld le bi\" data-selectable-paragraph=\"\">(androidTest) : The androidTest directory should contain the tests that run on real or virtual devices. Such tests include integration tests, end-to-end tests, and other tests where the JVM alone cannot validate your app\u2019s functionality.<\/li>\n<li id=\"f5d0\" class=\"kw kx gx hw b hx lf ib lg if lh ij li in lj ir lb lc ld le bi\" data-selectable-paragraph=\"\">(test) : The test directory should contain the tests that run on your local machine, such as unit tests. In contrast to the above, these can be tests that run on a local JVM.<\/li>\n<\/ul>\n<figure class=\"jw jx jy jz ek ka dy dz paragraph-image\">\n<div class=\"kb kc di kd bf ke\" role=\"button\">\n<div class=\"dy dz lk\"><img decoding=\"async\" loading=\"lazy\" class=\"bf kf kg c\" role=\"presentation\" src=\"\/blog\/wp-ttn-blog\/uploads\/2024\/01\/03aHXNXka-dvkA8e7.png\" alt=\"\" width=\"700\" height=\"324\" \/><\/div>\n<\/div><figcaption class=\"kh ki ea dy dz kj kk bd b be z fs\" data-selectable-paragraph=\"\">Test Directories<\/figcaption><\/figure>\n<p id=\"3096\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\"><strong class=\"hw gy\">AndroidJUnit4<\/strong><\/p>\n<p id=\"965d\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">Now we will integrate AndroidJUnit4 for instrumental testing.<\/p>\n<p id=\"84d1\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">A\u00a0<a class=\"ae kl\" href=\"https:\/\/github.com\/junit-team\/junit4\/wiki\/Test-runners\" target=\"_blank\" rel=\"noopener ugc nofollow\">test runner<\/a> is a JUnit component that runs tests. Without a test runner, your tests would not run. JUnit provides a default test runner that you get automatically.\u00a0<code class=\"et ll lm ln kn b\"><a class=\"ae kl\" href=\"https:\/\/github.com\/junit-team\/junit4\/wiki\/Test-runners#runwith-annotation\" target=\"_blank\" rel=\"noopener ugc nofollow\">@RunWith<\/a><\/code>\u00a0swaps out that default test runner.<\/p>\n<p id=\"b206\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">The\u00a0<code class=\"et ll lm ln kn b\"><a class=\"ae kl\" href=\"https:\/\/developer.android.com\/training\/testing\/junit-runner#kotlin\" target=\"_blank\" rel=\"noopener ugc nofollow\">AndroidJUnit4<\/a><\/code>\u00a0test runner allows for AndroidX Test to run your test differently depending on whether they are instrumented or local tests.<\/p>\n<figure class=\"jw jx jy jz ek ka dy dz paragraph-image\">\n<div class=\"kb kc di kd bf ke\" role=\"button\">\n<div class=\"dy dz lo\"><img decoding=\"async\" loading=\"lazy\" class=\"bf kf kg c\" role=\"presentation\" src=\"\/blog\/wp-ttn-blog\/uploads\/2024\/01\/0Us09AFOjmeqwQ9I6.png\" alt=\"\" width=\"700\" height=\"448\" \/><\/div>\n<\/div><figcaption class=\"kh ki ea dy dz kj kk bd b be z fs\" data-selectable-paragraph=\"\">* Image from\u00a0<a class=\"ae kl\" href=\"https:\/\/developer.android.com\/codelabs\/advanced-android-kotlin-training-testing-basics\" target=\"_blank\" rel=\"noopener ugc nofollow\">https:\/\/developer.android.com\/codelabs\/advanced-android-kotlin-training-testing-basics<\/a><\/figcaption><\/figure>\n<p id=\"7e82\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">Testing has three annotation:<\/p>\n<p id=\"6973\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">1.@Before : this is where all the setup code goes for setting up components like Viewmodel, Repository, database, application context, etc.<\/p>\n<p id=\"ae0f\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">2.@Close : this is the place where we close your resources that we will be using for testing like databases ,files etc.<\/p>\n<p id=\"35db\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">3.@Test : this is where we write our test that we want to check and assert.\u00a0<strong class=\"hw gy\">All the test statements end with Assert.<\/strong><\/p>\n<pre class=\"jw jx jy jz ek km kn ko bn kp kq bi\"><span id=\"91c9\" class=\"kr it gx kn b be ks kt l ku kv\" data-selectable-paragraph=\"\"><span class=\"hljs-meta\">@RunWith(AndroidJUnit4::class)<\/span>\r\n<span class=\"hljs-keyword\">class<\/span> <span class=\"hljs-title.class\">IntegrationTestMLKit<\/span> {\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">var<\/span> mSelectedImage: Bitmap? =link <span class=\"hljs-literal\">null<\/span>\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">var<\/span> image: InputImage? = <span class=\"hljs-literal\">null<\/span>\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">lateinit<\/span> <span class=\"hljs-keyword\">var<\/span> viewModel: SearchViewModel\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">lateinit<\/span> <span class=\"hljs-keyword\">var<\/span> repo: DrugRepository\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">lateinit<\/span> <span class=\"hljs-keyword\">var<\/span> db: AppDatabase\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-keyword\">val<\/span> drugAPI = RetrofitInstance.api\r\n\r\n<span class=\"hljs-comment\">\/**\r\n * setting up the required classes and instances\r\n *\/<\/span>\r\n <span class=\"hljs-meta\">@Before<\/span>\r\n <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">setup<\/span><span class=\"hljs-params\">()<\/span><\/span> {\r\n <span class=\"hljs-keyword\">val<\/span> appContext = InstrumentationRegistry.getInstrumentation().context\r\n  mSelectedImage = getBitmapFromAssets(appContext, \u201czyrtec.jpg\u201d)\r\n image = InputImage.fromBitmap(mSelectedImage!!, <span class=\"hljs-number\">0<\/span>)\r\n db = Room.inMemoryDatabaseBuilder(\r\n ApplicationProvider.getApplicationContext(),\r\n AppDatabase::<span class=\"hljs-keyword\">class<\/span>.java).allowMainThreadQueries().build()\r\n repo = DrugRepository(drugAPI, db)<span class=\"hljs-comment\">\/\/ repo instance<\/span>\r\n <span class=\"hljs-keyword\">val<\/span> dataSource = SearchViewModel(repo)<span class=\"hljs-comment\">\/\/<\/span>\r\n viewModel = dataSource\r\n }<\/span><\/pre>\n<pre class=\"lp km kn ko bn kp kq bi\"><span id=\"5c18\" class=\"kr it gx kn b be ks kt l ku kv\" data-selectable-paragraph=\"\"><span class=\"hljs-meta\">@After<\/span>\r\n <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">closeDb<\/span><span class=\"hljs-params\">()<\/span><\/span> {\r\n db.close() }\r\n<span class=\"hljs-comment\">\/*<\/span><\/span><\/pre>\n<pre class=\"lp km kn ko bn kp kq bi\"><span id=\"937a\" class=\"kr it gx kn b be ks kt l ku kv\" data-selectable-paragraph=\"\">* Function to test the Text scanner\r\n *\/\r\n <span class=\"hljs-meta\">@Test<\/span>\r\n <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">testTextScanner<\/span><span class=\"hljs-params\">()<\/span><\/span> {\r\n <span class=\"hljs-keyword\">val<\/span> rawValue: MutableLiveData&lt;String&gt; = MutableLiveData&lt;String&gt;()\r\n <span class=\"hljs-keyword\">val<\/span> recognizer = TextRecognition.getClient(TextRecognizerOptions.DEFAULT_OPTIONS)\r\n recognizer.process(image!!)\r\n .addOnFailureListener { e -&gt; <span class=\"hljs-comment\">\/\/ Task failed with an exception<\/span>\r\n e.printStackTrace()\r\n }\r\n .addOnCompleteListener {\r\n <span class=\"hljs-keyword\">if<\/span>(it.isSuccessful) {\r\n it.result?.text?.let { itr -&gt; rawValue.value=itr }\r\n }\r\n }\r\n rawValue.getOrAwaitValue()?.let {\r\n integrateSearchText(it)\r\n }}<\/span><\/pre>\n<p id=\"98f2\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">In the above code, we are storing data from TextRecognition in the rawValue Livedata. InstrumentationRegistry.getInstrumentation().context is used to provide the context of the application that all the components can use. rawValue.getOrAwaitValue() : getOrAwaitValue() is a function for live data that waits until the Livedata (rawValue) has a value inside it.<\/p>\n<pre class=\"jw jx jy jz ek km kn ko bn kp kq bi\"><span id=\"ab2f\" class=\"kr it gx kn b be ks kt l ku kv\" data-selectable-paragraph=\"\"><span class=\"hljs-comment\">\/**\r\n * checking the scanned text has any response with api, if\r\n * so we are matching the scanned text with actual drug\r\n *\/<\/span>\r\n <span class=\"hljs-keyword\">private<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">integrateSearchText<\/span><span class=\"hljs-params\">(text: <span class=\"hljs-type\">String<\/span>)<\/span><\/span> {\r\n <span class=\"hljs-keyword\">var<\/span> result: String\r\n <span class=\"hljs-keyword\">val<\/span> expected = \u201ccetirizine hydrochloride\u201d\r\n println(\u201ctext $text\u201d)\r\n viewModel.getapproximateTerm(text)\r\n viewModel.suggestionList.getOrAwaitValue().let {\r\n result = it.suggestionGroup.sulinkggestionList.suggestion.toString()\r\n result = result.drop(<span class=\"hljs-number\">1<\/span>).dropLast(<span class=\"hljs-number\">1<\/span>)\r\n }\r\n println(\u201capi $result\u201d)\r\n assert(result.contains(expected))\r\n }<\/span><\/pre>\n<p id=\"9925\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">In the above function integrateSearchText(text: String), we are checking the response we are getting from suggestionList api call and matching it with the expected result. The assert function is used to check if the test passed or failed.<\/p>\n<h1 id=\"de37\" class=\"is it gx bd iu iv iw ix iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp bi\" data-selectable-paragraph=\"\">getOrAwaitValue(): live data extension function<\/h1>\n<p id=\"c187\" class=\"pw-post-body-paragraph hu hv gx hw b hx jq hz ia ib jr id ie if js ih ii ij jt il im in ju ip iq ir gq bi\" data-selectable-paragraph=\"\">Below is the implementation of getOrAwaitValue() function. You can change getOrAwaitValue as per your requirement.<\/p>\n<pre class=\"jw jx jy jz ek km kn ko bn kp kq bi\"><span id=\"8a70\" class=\"kr it gx kn b be ks kt l ku kv\" data-selectable-paragraph=\"\"><span class=\"hljs-keyword\">import<\/span> androidx.lifecycle.LiveData\r\n<span class=\"hljs-keyword\">import<\/span> androidx.lifecycle.Observer\r\n<span class=\"hljs-keyword\">import<\/span> java.util.concurrent.CountDownLatch\r\n<span class=\"hljs-keyword\">import<\/span> java.util.concurrent.TimeUnit\r\n<span class=\"hljs-keyword\">import<\/span> java.util.concurrenapp\/build\/reports\/androidTestst.TimeoutException\r\n<span class=\"hljs-comment\">\/**\r\nthis class is created for observing Live data\r\n *\/<\/span>\r\n<span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-type\">&lt;T&gt;<\/span> LiveData<span class=\"hljs-type\">&lt;T&gt;<\/span>.<span class=\"hljs-title\">getOrAwaitValue<\/span><span class=\"hljs-params\">()<\/span><\/span> : T{\r\n <span class=\"hljs-keyword\">var<\/span> <span class=\"hljs-keyword\">data<\/span>: T? = <span class=\"hljs-literal\">null<\/span>\r\n <span class=\"hljs-keyword\">val<\/span> latch = CountDownLatch(<span class=\"hljs-number\">1<\/span>)\r\n <span class=\"hljs-keyword\">val<\/span> observer = <span class=\"hljs-keyword\">object<\/span> : Observer&lt;T&gt; {\r\n <span class=\"hljs-keyword\">override<\/span> <span class=\"hljs-function\"><span class=\"hljs-keyword\">fun<\/span> <span class=\"hljs-title\">onChanged<\/span><span class=\"hljs-params\">(t: <span class=\"hljs-type\">T<\/span>)<\/span><\/span> {\r\n <span class=\"hljs-keyword\">data<\/span> = t\r\n <span class=\"hljs-keyword\">this<\/span><span class=\"hljs-symbol\">@getOrAwaitValue<\/span>.removeObserver(<span class=\"hljs-keyword\">this<\/span>)\r\n latch.countDown()\r\n }\r\n }\r\n <span class=\"hljs-keyword\">this<\/span>.observeForever(observer)\r\n <span class=\"hljs-keyword\">try<\/span> {\r\n  <span class=\"hljs-keyword\">if<\/span> (!latch.await(<span class=\"hljs-number\">18<\/span>, TimeUnit.SECONDS)) {\r\n  <span class=\"hljs-keyword\">throw<\/span> TimeoutException(\u201cLive Data Never gets its value\u201d)\r\n  }\r\n }\r\n <span class=\"hljs-keyword\">finally<\/span> {\r\n <span class=\"hljs-keyword\">this<\/span>.removeObserver(observer)\r\n }\r\n <span class=\"hljs-keyword\">return<\/span> <span class=\"hljs-keyword\">data<\/span> <span class=\"hljs-keyword\">as<\/span> T\r\n}<\/span><\/pre>\n<p id=\"e988\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">This is a fairly complicated method. It creates a Kotlin extension function called getOrAwaitValue which adds an observer, gets the LiveData value, and then cleans up the observer \u2014 basically a short, reusable version of the observeForever code shown above. Read the link below for more information\u00a0<a class=\"ae kl\" href=\"https:\/\/medium.com\/androiddevelopers\/unit-testing-livedata-and-other-common-observability-problems-bb477262eb04\" rel=\"noopener\">link<\/a>.<\/p>\n<h1 id=\"e2a2\" class=\"is it gx bd iu iv iw ix iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp bi\" data-selectable-paragraph=\"\">Test Result<\/h1>\n<p id=\"ab5f\" class=\"pw-post-body-paragraph hu hv gx hw b hx jq hz ia ib jr id ie if js ih ii ij jt il im in ju ip iq ir gq bi\" data-selectable-paragraph=\"\">The results of the tests are stored in the app\/build\/reports\/androidTests folder.<\/p>\n<p id=\"6729\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">Inside the folder, you will find an index.html file.<\/p>\n<p id=\"1900\" class=\"pw-post-body-paragraph hu hv gx hw b hx hy hz ia ib ic id ie if ig ih ii ij ik il im in io ip iq ir gq bi\" data-selectable-paragraph=\"\">Inside index.html you will find a Test Summary of all the tests that you have executed.<\/p>\n<figure class=\"jw jx jy jz ek ka dy dz paragraph-image\">\n<div class=\"kb kc di kd bf ke\" role=\"button\">\n<div class=\"dy dz jv\"><img decoding=\"async\" loading=\"lazy\" class=\"bf kf kg c\" role=\"presentation\" src=\"\/blog\/wp-ttn-blog\/uploads\/2024\/01\/0xGNNG9yr-Dtq_z43.png\" alt=\"\" width=\"700\" height=\"393\" \/><\/div>\n<\/div><figcaption class=\"kh ki ea dy dz kj kk bd b be z fs\" data-selectable-paragraph=\"\">Index.html (app\/build\/reports\/androidTests)<\/figcaption><\/figure>\n<h1 id=\"48ce\" class=\"is it gx bd iu iv iw ix iy iz ja jb jc jd je jf jg jh ji jj jk jl jm jn jo jp bi\" data-selectable-paragraph=\"\">Conclusion<\/h1>\n<p><span data-preserver-spaces=\"true\">Testing an android application was a tough task, but with the help of\u00a0<\/span><strong><span data-preserver-spaces=\"true\">AndroidJUnit4<\/span><\/strong><span data-preserver-spaces=\"true\">, we can quickly write test cases for our android application.<\/span><\/p>\n<p><span data-preserver-spaces=\"true\">Read this<a href=\"https:\/\/developer.android.com\/training\/testing\/fundamentals\"> link<\/a> to set up and understand what testing architecture we should follow.<\/span><\/p>\n<\/div>\n<\/section>\n<\/div>\n<\/div>\n<\/article>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"m tz ul ab cl vi vj vk\">\n<div class=\"vl aw ax vm vn ab q c\">\n<div>\n<div class=\"bk\" aria-hidden=\"false\" aria-describedby=\"138\" aria-labelledby=\"138\">\n<div class=\"bk bf\" aria-hidden=\"false\">\n<div class=\"bk\" aria-hidden=\"false\" aria-describedby=\"creatorActionOverflowMenu\" aria-labelledby=\"creatorActionOverflowMenu\">\n<div class=\"wh l fy\"><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"ab cl\">\n<div class=\"do bf dp dq dr ds\"><\/div>\n<\/div>\n<div class=\"l\">\n<div class=\"l bv ml\">\n<div class=\"l ml\">\n<div class=\"ns nt l bv\">\n<div class=\"ab cl\">\n<div class=\"do bf dp dq dr ds\">\n<div class=\"ab q em\"><\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<\/div>\n<div class=\"ap-custom-wrapper\"><\/div><!--ap-custom-wrapper-->","protected":false},"excerpt":{"rendered":"<p>Introduction Instrumented tests run on Android devices, whether physical or emulated. As such, they can take advantage of the Android framework APIs. Instrumented tests, therefore, provide more fidelity than local tests, though they run much more slowly. * Image from\u00a0https:\/\/developer.android.com\/training\/testing\/fundamentals Set up your testing environment In your app\u2019s top-level build.gradle file, you need to specify [&hellip;]<\/p>\n","protected":false},"author":1504,"featured_media":0,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"iawp_total_views":18},"categories":[518,1772,1816],"tags":[5063],"aioseo_notices":[],"_links":{"self":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55700"}],"collection":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/users\/1504"}],"replies":[{"embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/comments?post=55700"}],"version-history":[{"count":11,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55700\/revisions"}],"predecessor-version":[{"id":59782,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/posts\/55700\/revisions\/59782"}],"wp:attachment":[{"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/media?parent=55700"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/categories?post=55700"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.tothenew.com\/blog\/wp-json\/wp\/v2\/tags?post=55700"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}