{"data":{"allMarkdownRemark":{"edges":[{"node":{"id":"a7cdd55d-a270-5c8c-be42-5c2c15c043f0","frontmatter":{"category":"Coding","title":"Testing your isolated Fragments with Koin","date":"2019-09-09","summary":"This blog post explains how you could set up your environment in order to test your fragments in isolation from other parts of your application","thumbnail":{"relativePath":"pages/testing-isolated-fragments-with-koin/thumbnail.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAUCAYAAACNiR0NAAAACXBIWXMAAAsTAAALEwEAmpwYAAAEcklEQVQ4y5WUbUxTVxjHL2UxCouJbsk+7MvmErNsH7b4YX4wsg0nU6RbXEXKS3lxMCm1paGIaJ1ji04Z08Eob8MhaGCSwRZIkPEqVSgKZVJKLb194basyHiZa0tfGG2fPfde6sQsLjvJP885zznP7z7n3PMcYoksIZZNcoJuDuPZsBWzkEM81uA9gnCNH2N8MEgQDzWniKc25xS7wEEWhYV8S+aarQ7Tl286jOdfCvmW7whY6Nq4IjeRUEgSmX7IPmoO8gsG9rupIdJtkpd5TPmLXlK66tFLvMuTuSrH5Mld9Ly6jhuukKZxSnPiwy5kcNfASethf0ydZ2BWfctGt7HgNiwVwl+kCLy6o+CdyAK4nwm+sQxwjYl4T+4OwREh6JnD77JOnyEnnNm6vvBzmD8O3slPfB5NZsAzlh703E0OBEeTYGX0CFj7Zd+KuanPVUr5u74R8raVCg9t/+54+st0bFWeIOxc6j7iTPw7LPTexPgGlzaXDNzPAgQF3HdTgu4hftAzlAyLt4W3dL3F0ReFSdcVEv4qnpe/XMz3XcrmzRXx9zCEc6n7mfP9NH4tS7uufqtzTLjsG00GGuRW8vx+FR9mbxVU0fNfZ8W3VObydQgzVeYmAdpV3GZf8RHugpwXtYNe81lC9D+3Y3yiN+JPVaZ9ZegQuPoPBlxd3KC78wC4b8TOUs281rqTaXApJ3FBIU6AyzIB1OalgELMX7ySLwA8u19oRnFGXBiTIXRvZ8jzStE1GOaBqyPW52zbF3T+tDfoad0Dwba9MN/4PnReiH+gkH3cUJ2fVl+dn06rsUqW1nQ2dX8Rc50AiE10h7p5mgFODtZuW+xMXoTOGHA2v+13NkX5HVd3+53fvxVYbtgJv6kbneaZ+UkLRekslE1nsdq0ZspqGNdO9nR190TSDM3EBHuX7T1sJej6Lr4x15425mqJhZUfY8DdFA3z1z/ymYabA6TZBlZqGiiKYjU9DTarFUZGRpZ1Ot2NmZmZLew9vClg7IPetZLD1PU9X0VTHflZ5nZpnFar3m0wWb1GkgSDwRAIiSTJldnZWVCpVFKTySRHH1u/+r4Swt3O/m5bdx7n38qTNOi77XY70BBUkAYajcagVquFgYGB17BfjT7ho4B7vXXEw4549gPdJYSpU86xtYvCzYP1G2gfBuzELJitYqAfx2Cz2UCtVlN6vX4Ax7UajYbz1EcDAxk7NTXFLMTMeOhbslgsQMMR0IDZPY/AF0MxSqUybB3k8VcD+xxaZUIep+1y6TPMXxwbfcGg13+g007sIP5PKzuW8J9rrgxbnr2qWdhU9+tcRM3PvZtr1HORla1dG9ctol+NMlFCKMNorF1uuSQxhu6jPYzzUZUFmSkVhdlCRWF2uuLEUQEqQyEXf6g4kS2rOC15dR2wXJzInIFCnPgKQjRYXo1oe/AxaEJ4P/bvoK8KS1CJ+oFWOWs7Uf2ohCeA/JDdjMH5CI5DewrVgRKh/wBm+joqD8cHURKUEMfZaGUV0uQtfwP/KbEPkxHssgAAAABJRU5ErkJggg==","width":280,"height":280,"src":"/static/3002cc6db63b27d120e79145783a1750/b2831/thumbnail.png","srcSet":"/static/3002cc6db63b27d120e79145783a1750/b2831/thumbnail.png 1x"}}},"authorName":"Oleg Osipenko","authorDescription":"Senior Software Engineer","authorAvatar":{"relativePath":"pages/testing-isolated-fragments-with-koin/avatar.jpg","childImageSharp":{"resolutions":{"base64":"data:image/jpeg;base64,/9j/2wBDABALDA4MChAODQ4SERATGCgaGBYWGDEjJR0oOjM9PDkzODdASFxOQERXRTc4UG1RV19iZ2hnPk1xeXBkeFxlZ2P/2wBDARESEhgVGC8aGi9jQjhCY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2NjY2P/wgARCAAUABQDASIAAhEBAxEB/8QAFwABAQEBAAAAAAAAAAAAAAAAAAQDAf/EABYBAQEBAAAAAAAAAAAAAAAAAAIAA//aAAwDAQACEAMQAAABvxphrZG0EPTN4Bn/xAAcEAABBQADAAAAAAAAAAAAAAACAAEDERIEIUH/2gAIAQEAAQUCMe3HKpTU69LkszxyFqUy1a//xAAWEQADAAAAAAAAAAAAAAAAAAABIDH/2gAIAQMBAT8BET//xAAXEQADAQAAAAAAAAAAAAAAAAAAAREQ/9oACAECAQE/AW3S7//EABkQAQADAQEAAAAAAAAAAAAAAAEAEDERcf/aAAgBAQAGPwIJtFZFXvs2v//EABoQAQEBAQEBAQAAAAAAAAAAAAEAESExUWH/2gAIAQEAAT8hxA4Prax0i9GTYNSGfefshNWsqhiiOSvft//aAAwDAQACAAMAAAAQpBd//8QAGBEBAQADAAAAAAAAAAAAAAAAAQAQEUH/2gAIAQMBAT8QAzTcx//EABURAQEAAAAAAAAAAAAAAAAAABBB/9oACAECAQE/EAVP/8QAHBABAQEBAAIDAAAAAAAAAAAAAREAITFBgZHR/9oACAEBAAE/EGgFUPPPR96QjAi/JqtWdBTjHT0kCCvN/MUGjjrFKJRrNDGeA876ympRXm//2Q==","width":50,"height":50,"src":"/static/4d1dd08092290e44fd34c92f78d9904e/d2d31/avatar.jpg","srcSet":"/static/4d1dd08092290e44fd34c92f78d9904e/d2d31/avatar.jpg 1x,\n/static/4d1dd08092290e44fd34c92f78d9904e/0b804/avatar.jpg 1.5x,\n/static/4d1dd08092290e44fd34c92f78d9904e/753c3/avatar.jpg 2x,\n/static/4d1dd08092290e44fd34c92f78d9904e/31ca8/avatar.jpg 3x"}}},"headerImage":{"relativePath":"pages/testing-isolated-fragments-with-koin/headerImage.png","childImageSharp":{"resolutions":{"base64":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABQAAAAECAYAAACOXx+WAAAACXBIWXMAAAsSAAALEgHS3X78AAAAvklEQVQY02NggIIvV/LB9Pvb7WzfrmRs+Hw+vQgmt35mb+DqSS2fV01ujwLxF3dWMZ0/eYwBL/hwNIURRL+7USf8aVfQn/frfLp0p/xnD3JSZ7/14LHdvYePXt66ez8dpObk8WOMj1++wW+gMsiVW3zB7OcLfNVfLfbSALFvCTIwTMwINFrSWRU2rSzFqSXahQkkPqU4kYEo8Hm9F5x9Zl4qY//kOQxT8iI1OqKd5SZmhcouaCoEy03OjcCqHwADLUswHlaKbgAAAABJRU5ErkJggg==","width":1280,"height":280,"src":"/static/a77f9e0124a66d21b204dc560d751ee8/26421/headerImage.png","srcSet":"/static/a77f9e0124a66d21b204dc560d751ee8/26421/headerImage.png 1x"}}}},"html":"<p>UI-tests are a necessary part of our development routine in AUTO1. Although that wasn’t the case a while ago. One of the issues, which was blocking developers from writing and running UI-tests, was the need to set up UI-tests. Of course, to test the screen in isolation you need to have some architecture, employ the SOLID principles, especially Dependency inversion. With proper architecture it’s easy to substitute dependencies inside screen under the test with fakes or mocks. But even with good architecture you need to provide these mock implementations. And it’s not always obvious how to make your DI framework to provide mocks for tests.</p>\n<p>Recently we started a brand new project from scratch. And we decided to give <a href=\"https://insert-koin.io/\">Koin</a> a try. Why Koin and not Dagger? — Just because Koin offers concise and minimalistic syntax and it uses Kotlin. Also, important for us was the question of code generation. Although Google announced that in new versions of Android Gradle plug-in they made kapt incremental, we still didn’t want to add this extra burden to our build process. Simultaneously Koin 2.0 was announced at the same time. That’s how we found ourselves facing question: how to provide mock dependencies to our UI-tests?</p>\n<h2>Let’s start with fragment…</h2>\n<p>Inside our fragments we inject number of dependencies, typically they include viewmodels:</p>\n<div class=\"gatsby-highlight\" data-language=\"kotlin\"><pre class=\"language-kotlin\"><code class=\"language-kotlin\"><span class=\"token keyword\">private</span> <span class=\"token keyword\">val</span> fragmentViewModel<span class=\"token operator\">:</span> EmailLoginFragmentViewModel <span class=\"token keyword\">by</span> <span class=\"token function\">viewModel</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span></code></pre></div>\n<p>That’s exactly what we want to substitute with mocks. To do so we need a custom Application class, which will start Koin with our test module, not the real one.</p>\n<div class=\"gatsby-highlight\" data-language=\"kotlin\"><pre class=\"language-kotlin\"><code class=\"language-kotlin\"><span class=\"token keyword\">class</span> KoinTestApp<span class=\"token operator\">:</span> <span class=\"token function\">Application</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">override</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">onCreate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">onCreate</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    startKoin <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">androidLogger</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">androidContext</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">this</span><span class=\"token label symbol\">@KoinTestApp</span><span class=\"token punctuation\">)</span>\n    <span class=\"token function\">modules</span><span class=\"token punctuation\">(</span><span class=\"token function\">emptyList</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">internal</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">injectModule</span><span class=\"token punctuation\">(</span>module<span class=\"token operator\">:</span> Module<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">loadKoinModules</span><span class=\"token punctuation\">(</span>module<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>We start our Koin instance inside <code class=\"language-text\">onCreate()</code> method, and we pass <code class=\"language-text\">emptyList()</code> of modules. We also have a method <code class=\"language-text\">injectModule()</code> which accepts our test module. Since we already started our application, we are using method <code class=\"language-text\">loadKoinModules()</code> to add this test module to the graph.</p>\n<h2>How to run custom application</h2>\n<p>But we need to somehow start our test application class. We cannot use <code class=\"language-text\">AndroidManifest</code>  inside <code class=\"language-text\">androidTest</code> folder, because manifest merger will ignore it if we set our test application inside Manifest like this: <code class=\"language-text\">&lt;application name=\".KoinTestApp\"></code>. So we could use a custom test runner for that purpose. <code class=\"language-text\">AndroidJUnitRunner</code> class has a <code class=\"language-text\">newApplication()</code> method. And we can pass our test application name there, making our test runner to start our test application instead of a real one.</p>\n<div class=\"gatsby-highlight\" data-language=\"kotlin\"><pre class=\"language-kotlin\"><code class=\"language-kotlin\"><span class=\"token keyword\">class</span> KoinTestRunner<span class=\"token operator\">:</span> <span class=\"token function\">AndroidJUnitRunner</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">override</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">newApplication</span><span class=\"token punctuation\">(</span>\n    cl<span class=\"token operator\">:</span> ClassLoader<span class=\"token operator\">?</span><span class=\"token punctuation\">,</span> \n    className<span class=\"token operator\">:</span> String<span class=\"token operator\">?</span><span class=\"token punctuation\">,</span> \n    context<span class=\"token operator\">:</span> Context<span class=\"token operator\">?</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Application <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">return</span> <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">newApplication</span><span class=\"token punctuation\">(</span>cl<span class=\"token punctuation\">,</span> KoinTestApp<span class=\"token operator\">::</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">.</span>java<span class=\"token punctuation\">.</span>name<span class=\"token punctuation\">,</span> context<span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>Then we need to change our <code class=\"language-text\">build.gradle</code> inside our app module:</p>\n<div class=\"gatsby-highlight\" data-language=\"groovy\"><pre class=\"language-groovy\"><code class=\"language-groovy\">android <span class=\"token punctuation\">{</span>\n  defaultConfig <span class=\"token punctuation\">{</span>\n    …\n    …\n    testInstrumentationRunner “path<span class=\"token punctuation\">.</span>to<span class=\"token punctuation\">.</span>your<span class=\"token punctuation\">.</span><span class=\"token keyword\">package</span><span class=\"token punctuation\">.</span>KoinTestRunner”\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<p>And don’t forget to disable animations for UI-tests:</p>\n<div class=\"gatsby-highlight\" data-language=\"groovy\"><pre class=\"language-groovy\"><code class=\"language-groovy\">android <span class=\"token punctuation\">{</span>\n  testOptions <span class=\"token punctuation\">{</span>\n    animationsDisabled <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span></code></pre></div>\n<h2>Test rule for fragments</h2>\n<p>We are almost done. We only need to write our test and provide our test module to it. We are using our custom fragment test rule, which provides a couple of methods for submitting your fragment and mock test module. But you could use the same approach for activities.</p>\n<div class=\"gatsby-highlight\" data-language=\"kotlin\"><pre class=\"language-kotlin\"><code class=\"language-kotlin\"><span class=\"token keyword\">abstract</span> <span class=\"token keyword\">class</span> FragmentTestRule<span class=\"token operator\">&lt;</span>F<span class=\"token operator\">:</span> Fragment<span class=\"token operator\">></span><span class=\"token operator\">:</span> \n  ActivityTestRule<span class=\"token operator\">&lt;</span>FragmentActivity<span class=\"token operator\">></span><span class=\"token punctuation\">(</span>FragmentActivity<span class=\"token operator\">::</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">.</span>java<span class=\"token punctuation\">,</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n  \n  <span class=\"token keyword\">override</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">afterActivityLaunched</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">afterActivityLaunched</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    activity<span class=\"token punctuation\">.</span><span class=\"token function\">runOnUiThread</span> <span class=\"token punctuation\">{</span>\n      <span class=\"token keyword\">val</span> fm <span class=\"token operator\">=</span> activity<span class=\"token punctuation\">.</span>supportFragmentManager\n      <span class=\"token keyword\">val</span> transaction <span class=\"token operator\">=</span> fm<span class=\"token punctuation\">.</span><span class=\"token function\">beginTransaction</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n      transaction<span class=\"token punctuation\">.</span><span class=\"token function\">replace</span><span class=\"token punctuation\">(</span>android<span class=\"token punctuation\">.</span>R<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">.</span>content<span class=\"token punctuation\">,</span> <span class=\"token function\">createFragment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n        <span class=\"token punctuation\">.</span><span class=\"token function\">commit</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n  \n  <span class=\"token keyword\">override</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">beforeActivityLaunched</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">super</span><span class=\"token punctuation\">.</span><span class=\"token function\">beforeActivityLaunched</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n    <span class=\"token keyword\">val</span> application <span class=\"token operator\">=</span> InstrumentationRegistry<span class=\"token punctuation\">.</span><span class=\"token function\">getInstrumentation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">.</span>targetContext<span class=\"token punctuation\">.</span>applicationContext <span class=\"token keyword\">as</span> KoinTestApp\n    application<span class=\"token punctuation\">.</span><span class=\"token function\">injectModule</span><span class=\"token punctuation\">(</span><span class=\"token function\">getModule</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">protected</span> <span class=\"token keyword\">abstract</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">createFragment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> F\n  \n  <span class=\"token keyword\">protected</span> <span class=\"token keyword\">abstract</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">getModule</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Module\n  \n  <span class=\"token keyword\">fun</span> <span class=\"token function\">launch</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">launchActivity</span><span class=\"token punctuation\">(</span><span class=\"token function\">Intent</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token punctuation\">)</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">fun</span> <span class=\"token operator\">&lt;</span>F<span class=\"token operator\">:</span> Fragment<span class=\"token operator\">></span> <span class=\"token function\">createRule</span><span class=\"token punctuation\">(</span>fragment<span class=\"token operator\">:</span> F<span class=\"token punctuation\">,</span> module<span class=\"token operator\">:</span> Module<span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> FragmentTestRule<span class=\"token operator\">&lt;</span>F<span class=\"token operator\">></span> <span class=\"token operator\">=</span> \n  <span class=\"token keyword\">object</span><span class=\"token operator\">:</span> FragmentTestRule<span class=\"token operator\">&lt;</span>F<span class=\"token operator\">></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">override</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">createFragment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> F <span class=\"token operator\">=</span> fragment\n\n    <span class=\"token keyword\">override</span> <span class=\"token keyword\">fun</span> <span class=\"token function\">getModule</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span><span class=\"token operator\">:</span> Module <span class=\"token operator\">=</span> module\n  <span class=\"token punctuation\">}</span></code></pre></div>\n<p>I am using default Android <code class=\"language-text\">FragmentActivity</code> to host fragment under test. So we need to mention this activity in the manifest. For that purpose I created instance of <code class=\"language-text\">AndroidManifest</code> inside debug variant in my app module:</p>\n<div class=\"gatsby-highlight\" data-language=\"xml\"><pre class=\"language-xml\"><code class=\"language-xml\"><span class=\"token prolog\">&lt;?xml version=\"1.0\" encoding=\"utf-8\"?></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>manifest</span>\n  <span class=\"token attr-name\"><span class=\"token namespace\">xmlns:</span>android</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>http://schemas.android.com/apk/res/android<span class=\"token punctuation\">\"</span></span>\n  <span class=\"token attr-name\">package</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>com.github.olegosipenko.kointestsample<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>application</span><span class=\"token punctuation\">></span></span>\n    <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;</span>activity</span>\n      <span class=\"token attr-name\"><span class=\"token namespace\">android:</span>theme</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>@style/AppTheme<span class=\"token punctuation\">\"</span></span>\n      <span class=\"token attr-name\"><span class=\"token namespace\">android:</span>name</span><span class=\"token attr-value\"><span class=\"token punctuation attr-equals\">=</span><span class=\"token punctuation\">\"</span>androidx.fragment.app.FragmentActivity<span class=\"token punctuation\">\"</span></span><span class=\"token punctuation\">/></span></span>\n  <span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>application</span><span class=\"token punctuation\">></span></span>\n<span class=\"token tag\"><span class=\"token tag\"><span class=\"token punctuation\">&lt;/</span>manifest</span><span class=\"token punctuation\">></span></span></code></pre></div>\n<h2>Test itself</h2>\n<p>Finally, our test class could look like this:</p>\n<div class=\"gatsby-highlight\" data-language=\"kotlin\"><pre class=\"language-kotlin\"><code class=\"language-kotlin\"><span class=\"token annotation builtin\">@RunWith</span><span class=\"token punctuation\">(</span>AndroidJUnit4ClassRunner<span class=\"token operator\">::</span><span class=\"token keyword\">class</span><span class=\"token punctuation\">)</span>\n<span class=\"token keyword\">class</span> EmailLoginFragmentTest <span class=\"token punctuation\">{</span>\n  <span class=\"token keyword\">private</span> <span class=\"token keyword\">val</span> fragmentViewModel<span class=\"token operator\">:</span> EmailLoginFragmentViewModel <span class=\"token operator\">=</span> <span class=\"token function\">mockk</span><span class=\"token punctuation\">(</span>relaxed <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span>\n  <span class=\"token keyword\">private</span> <span class=\"token keyword\">val</span> fragment <span class=\"token operator\">=</span> <span class=\"token function\">EmailLoginFragment</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token annotation builtin\">@get:Rule</span>\n  <span class=\"token keyword\">val</span> fragmentRule <span class=\"token operator\">=</span> <span class=\"token function\">createRule</span><span class=\"token punctuation\">(</span>fragment<span class=\"token punctuation\">,</span> module <span class=\"token punctuation\">{</span>\n    <span class=\"token function\">single</span><span class=\"token punctuation\">(</span><span class=\"token keyword\">override</span> <span class=\"token operator\">=</span> <span class=\"token boolean\">true</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n      fragmentViewModel\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span><span class=\"token punctuation\">)</span>\n\n  <span class=\"token annotation builtin\">@Test</span>\n  <span class=\"token keyword\">fun</span> <span class=\"token function\">testBasicInvocation</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    onScreen<span class=\"token operator\">&lt;</span>EmailLoginForm<span class=\"token operator\">></span> <span class=\"token punctuation\">{</span>\n      emailField <span class=\"token punctuation\">{</span> <span class=\"token function\">typeText</span><span class=\"token punctuation\">(</span>EMAIL<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n      passwordField <span class=\"token punctuation\">{</span> <span class=\"token function\">typeText</span><span class=\"token punctuation\">(</span>PASSWORD<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n      loginButton<span class=\"token punctuation\">.</span><span class=\"token function\">click</span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span>\n      verify <span class=\"token punctuation\">{</span>\n        fragmentViewModel<span class=\"token punctuation\">.</span><span class=\"token function\">loginWithCredentials</span><span class=\"token punctuation\">(</span>EMAIL<span class=\"token punctuation\">,</span> PASSWORD<span class=\"token punctuation\">)</span>\n      <span class=\"token punctuation\">}</span>\n    <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n\n  <span class=\"token keyword\">class</span> EmailLoginForm<span class=\"token operator\">:</span> Screen<span class=\"token operator\">&lt;</span>EmailLoginForm<span class=\"token operator\">></span><span class=\"token punctuation\">(</span><span class=\"token punctuation\">)</span> <span class=\"token punctuation\">{</span>\n    <span class=\"token keyword\">val</span> emailField <span class=\"token operator\">=</span> KEditText <span class=\"token punctuation\">{</span> <span class=\"token function\">withId</span><span class=\"token punctuation\">(</span>R<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">.</span>textFieldEmail<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">val</span> passwordField <span class=\"token operator\">=</span> KEditText <span class=\"token punctuation\">{</span> <span class=\"token function\">withId</span><span class=\"token punctuation\">(</span>R<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">.</span>textFieldPassword<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n    <span class=\"token keyword\">val</span> loginButton <span class=\"token operator\">=</span> KButton <span class=\"token punctuation\">{</span> <span class=\"token function\">withId</span><span class=\"token punctuation\">(</span>R<span class=\"token punctuation\">.</span>id<span class=\"token punctuation\">.</span>buttonLogin<span class=\"token punctuation\">)</span> <span class=\"token punctuation\">}</span>\n  <span class=\"token punctuation\">}</span>\n<span class=\"token punctuation\">}</span>\n\n<span class=\"token keyword\">private</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">val</span> EMAIL <span class=\"token operator\">=</span> <span class=\"token string\">\"some@email.com\"</span>\n<span class=\"token keyword\">private</span> <span class=\"token keyword\">const</span> <span class=\"token keyword\">val</span> PASSWORD <span class=\"token operator\">=</span> <span class=\"token string\">\"password\"</span></code></pre></div>\n<p>Here we are using <a href=\"http://github.com/agoda-com/Kakao/\">Kakao</a>, it’s a nice tool to simplify working with Espresso tests. It provides implementation of <a href=\"https://martinfowler.com/bliki/PageObject.html\">Page Object pattern</a> and allows you to abstract interactions with your UI behind the abstract <a href=\"https://github.com/agoda-com/Kakao/blob/master/kakao/src/main/kotlin/com/agoda/kakao/screen/Screen.kt\">Screen</a> objects. Using Kakao you can improve maintainability of your tests, so if you are not using it yet, give it a try. Also we are using <a href=\"https://mockk.io/\">Mockk</a> for mocking, which uses all the power Kotlin gives us.</p>\n<p>That’s how with Koin, Kakao and Mockk you could easily test your fragments in isolation, making your life easier.</p>\n<p>You can check the source code for the sample <a href=\"https://github.com/olegosipenko/KoinTestApp\">here</a>.</p>","fields":{"slug":"/testing-isolated-fragments-with-koin/","tags":["android","koin","kakao","mockk","espresso","android fragments"]}}}]}},"pageContext":{"slug":"/tags/mockk","tag":"mockk","categories":["Architecture","Coding","DevOps","Engineering","ProjectManagement","QA","Social","TechRadar"]}}