<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Testing Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/testing/feed/" rel="self" type="application/rss+xml" />
	<link></link>
	<description>Kotlin &#38; Backend Tutorials - Learn Through Practice.</description>
	<lastBuildDate>Wed, 16 Apr 2025 04:49:37 +0000</lastBuildDate>
	<language>en-US</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	

<image>
	<url>https://blog.codersee.com/wp-content/uploads/2025/04/cropped-codersee_logo_circle_2-32x32.png</url>
	<title>Testing Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>MockK with Coroutines [5/5]</title>
		<link>https://blog.codersee.com/mockk-coroutines/</link>
					<comments>https://blog.codersee.com/mockk-coroutines/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 04 Mar 2025 17:55:48 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MockK]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=17512712</guid>

					<description><![CDATA[<p>In the last article in a series, we are going to learn everything we need to know to work with MockK and Kotlin coroutines. </p>
<p>The post <a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>At this point, we spent a lot of time exploring MockK features and syntax, so at this point, adding coroutines will be trivial, trust me😉</p>



<p>Of course, you can find the rest of the series on my blog, too:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li>MockK with Coroutines [5/5]</li>
</ul>



<h2 class="wp-block-heading" id="h-video-content">Video Content</h2>



<p>As always, if you prefer a video content, then please check out my latest YouTube video:</p>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><a href="https://blog.codersee.com/mockk-coroutines/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FW0nnZl4R6C0%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /><figcaption></figcaption></figure>


<h2 class="wp-block-heading" id="h-additional-imports">Additional Imports</h2>



<p>As the first step, let&#8217;s add the necessary import:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.10.1")</pre>



<p>This package provides utilities for testing coroutines.</p>



<p>And thanks to that, we can mock and test suspend functions.</p>



<h2 class="wp-block-heading">Code To Test</h2>



<p>Following, let&#8217;s introduce the suspended functions:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Eight(
    private val one: EightOne,
    private val two: EightTwo,
) {
    suspend fun funToTest(): String {
        return "${one.returnInt()} ${two.returnString()}"
    }
}

class EightOne {
    suspend fun returnInt(): Int = 10
}

class EightTwo {
    suspend fun returnString(): String = "Some String"
}</pre>



<p>And I know it does not make sense. But it is not important here😉</p>



<p>The important part is that we have suspended functions so we can start implementing tests.</p>



<h2 class="wp-block-heading">MockK with Coroutines</h2>



<p>As the next step, let&#8217;s try to implement the test &#8220;the old way&#8221;:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class EightTest {
    private val one: EightOne = mockk()
    private val two: EightTwo = mockk()

    private val eight = Eight(one, two)

    @Test
    fun `should return 1 codersee`() {
        every { one.returnInt() } returns 1
        every { two.returnString() } returns "codersee"

        val result = eight.funToTest()

        assertEquals("1 codersee", result)

        verifySequence {
            one.returnInt()
            two.returnString()
        }
    }
}</pre>



<p>As a result, we can see the compiler complaining about our suspended functions:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Suspend function 'returnInt' should be called only from a coroutine or another suspend function
Suspend function 'returnString' should be called only from a coroutine or another suspend function
Suspend function 'funToTest' should be called only from a coroutine or another suspend function</pre>



<p>So, as the first step, let&#8217;s add the <code>runTest</code> to get rid of the last error:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 1 codersee`() = runTest {</pre>



<p>The <code>runTest</code> is not related to the MockK itself. It comes from <code>kotlinx.coroutines</code> and executes our test body in a new coroutine, returning <code>TestResult</code> .</p>



<p>When it comes to MockK, then we can work with coroutines and suspended functions by simply adding the &#8220;co&#8221; suffix for all functions:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class EightTest {
    private val one: EightOne = mockk()
    private val two: EightTwo = mockk()

    private val eight = Eight(one, two)

    @Test
    fun `should return 1 codersee`() = runTest {
        coEvery { one.returnInt() } returns 1
        coEvery { two.returnString() } returns "codersee"

        val result = eight.funToTest()

        assertEquals("1 codersee", result)

        coVerifySequence {
            one.returnInt()
            two.returnString()
        }
    }
}</pre>



<p>And yes, this is that easy!😉</p>



<p>MockK comes with plenty of functions to work with suspend functions, like:</p>



<ul class="wp-block-list">
<li><code>coVerify</code></li>



<li><code>coEvery</code></li>



<li><code>coJustRun</code></li>



<li><code>coJustAwait</code></li>



<li><code>coAnswers</code></li>



<li>and many more😉</li>
</ul>



<h2 class="wp-block-heading">Issue With Spies</h2>



<p>Lastly, at the moment of writing, there is one issue with spies and coroutines in MockK. You can see all the details here: <a href="https://github.com/mockk/mockk/issues/554">https://github.com/mockk/mockk/issues/554</a></p>



<p>Assuming this is quite an old one, I wouldn&#8217;t expect it to be fixed in the near future.</p>



<p>But if that is the case, then please let me know in the comments below.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>That&#8217;s all for this series about MockK &#8211; the mocking library for Kotlin.</p>



<p>During our time together, we learned A LOT, and I believe you are ready to use it in your projects!</p>



<p>Let me know your thoughts in the comments below, and if you are looking for the other articles, then here you are:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li>MockK with Coroutines [5/5]</li>
</ul>
<p>The post <a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/mockk-coroutines/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MockK: Spy, Relaxed Mock, and Partial Mocking [4/5]</title>
		<link>https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/</link>
					<comments>https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 04 Mar 2025 17:55:42 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MockK]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=17512701</guid>

					<description><![CDATA[<p>In the fourth artcile in a series, we are going to learn what are MockK spies, relaxed mocks and how to do a partial mocking.</p>
<p>The post <a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spy, Relaxed Mock, and Partial Mocking [4/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>At this point, we know quite a lot about mocks, verification, and how to perform stubbings. In this lesson, we are going to expand our horizons and see additional features useful in day-to-day scenarios, like relaxed mocks.</p>



<p>Of course, you can find the rest of the series on my blog, too:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li><a href="MockK: Objects, Top-Level, and Extension Functions [3/5]">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li>MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<h2 class="wp-block-heading" id="h-video-content">Video Content</h2>



<p>As always, if you prefer a video content, then please check out my latest YouTube video:</p>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FyukKpPr_iBg%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /><figcaption></figcaption></figure>


<h2 class="wp-block-heading" id="h-mockk-relaxed-mock">MockK: Relaxed Mock</h2>



<p>What does a <strong>relaxed mock</strong> mean?</p>



<p>Well, long story short, it is <strong>a mock that returns some value for all functions</strong>. In other words, the value is returned even if we do not provide a stubbing.</p>



<p>To better understand, let&#8217;s take a look at the example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Five(
    private val one: FiveOne,
) {
    fun funToTest(): String {
        one.returnInt()
        return one.returnString()
    }
}

class FiveOne {
    fun returnInt(): Int = 10
    fun returnString(): String = "Some String"
}</pre>



<p>As we can see, the function we want to test invokes two another: <code>returnInt</code> and <code>returnString</code>.</p>



<p>And I am pretty sure that at this point, you know the result without even running the test:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class FiveTest {

    private val one: FiveOne = mockk()
    private val five = Five(one)

    @Test
    fun `should return mocked string`() {
        every { one.returnString() } returns "mocked"

        val result = five.funToTest()

        assertEquals("mocked", result)
    }
}</pre>



<p>That&#8217;s right, it fails, and MockK complains about missing answer:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">no answer found for FiveOne(#1).returnInt() among the configured answers: (FiveOne(#1).returnString()))
io.mockk.MockKException: no answer found for FiveOne(#1).returnInt() among the configured answers: (FiveOne(#1).returnString()))</pre>



<p>And as you may have guessed, a relaxed mock may help us here a bit. But how do we define it in MockK?</p>



<p>It&#8217;s easy; the only thing we need is to set up the <code>relaxed</code> flag on creation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private val one: FiveOne = mockk(relaxed = true)</pre>



<p>(When working with annotations, we can use <code>@RelaxedMockK</code> instead of <code>@MockK</code>)</p>



<p>So, now, when we repeat our test, <strong>it passes!</strong></p>



<p>Moreover, we could even completely skip the stubbing part:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return empty string`() {
    val result = five.funToTest()

    assertEquals("", result)
}</pre>



<p>But please don&#8217;t do that in your tests and treat them as a curiosity😉</p>



<p>And before we head to the next part, I just wanted to mention that <strong>for Unit-returning functions, we must set a separate flag- </strong><code><strong>relaxUnitFun</strong></code><strong> &#8211; to true:</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private val one: FiveOne = mockk(relaxed = true, relaxUnitFun = true)</pre>



<h2 class="wp-block-heading">Partial Mocking</h2>



<p>Nextly, let&#8217;s focus on the <strong>partial mocking.</strong></p>



<p>This technique, on the other hand, allows us to <strong>invoke the actual function</strong>.</p>



<p>Let&#8217;s take a look at the example of a new class to test:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Six(
    private val one: SixOne,
) {
    fun funToTest(): String {
        one.returnInt()
        return one.returnString()
    }
}

class SixOne {
    fun returnInt(): Int = 10
    fun returnString(): String = "Some String"
}</pre>



<p>As we can see, apart from the names, it works exactly the same as previously.</p>



<p>So, let&#8217;s take a look at the test:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class SixTest {

    private val one: SixOne = mockk()
    private val five = Six(one)

    @Test
    fun `should invoke actual functions`() {
        every { one.returnInt() } answers { callOriginal() }
        every { one.returnString() } answers { callOriginal() }

        val result = five.funToTest()

        assertEquals("Some String", result)
    }
}</pre>



<p>As we can see, in MockK, we can use the <code>answers { callOriginal() }</code>&nbsp; to invoke the actual function. And that&#8217;s why we get <em>&#8220;Some String&#8221;</em> value here.</p>



<h2 class="wp-block-heading">MockK Spy</h2>



<p>As the last step, let&#8217;s take a look at the <strong>spies</strong>. What are they?</p>



<p>Well, they are a mix of real objects with mocks. Whenever we do not specify any stubbing, the actual function is invoked.</p>



<p>So, the main difference between spies and partial mocking is that for a spy, the original function is invoked if we don&#8217;t write anything. In partial mocking, we must be explicit.</p>



<p>Let&#8217;s take a look at the code to test then. Again, this is a 1:1 copy of previous examples:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Seven(
    private val one: SevenOne,
) {
    fun funToTest(): String {
        one.returnInt()
        return one.returnString()
    }
}

class SevenOne {
    fun returnInt(): Int = 10
    fun returnString(): String = "Some String"
}</pre>



<p>Following, let&#8217;s implement a simple test with a MockK spy then:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class SevenTest {

    private val one: SevenOne = spyk(SevenOne())

    private val five = Seven(one)

    @Test
    fun `should invoke actual functions`() {
        val result = five.funToTest()

        assertEquals("Some String", result)
    }
}</pre>



<p>And we can see the interesting difference here- we pass the instance of the dependent object to the <code>spyk</code> . And although underneath a copy of that object will be used rather than the passed instance, this shows that <strong>spies are actual objects with mocking capabilities.</strong></p>



<p>Additionally, we can use a similar notation to <code>mockk</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private val one: SevenOne = spyk()
// or 
private val one = spyk&lt;SevenOne>()</pre>



<p>In this case, the default constructor will be invoked.</p>



<p>And if you are wondering when to use spies, and when to choose partial mocks, then I would say that partial mocks will be better whenever actual calls are rare, almost exceptional. If since the very beginning we want to mix actual resposnes with stubs, then spies will be more optiomal option.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>That&#8217;s all for the fourth article in a series in which we learned how to deal with MockK spies, relaxed mocks, and partial mocking.</p>



<p>Awesome! And without any further ado, let&#8217;s head to the next lesson:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li><a href="MockK: Objects, Top-Level, and Extension Functions [3/5]">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li>MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<p></p>
<p>The post <a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spy, Relaxed Mock, and Partial Mocking [4/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>MockK: Objects, Top-Level, and Extension Functions [3/5]</title>
		<link>https://blog.codersee.com/mockk-objects-top-level-extension-functions/</link>
					<comments>https://blog.codersee.com/mockk-objects-top-level-extension-functions/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 04 Mar 2025 17:55:29 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MockK]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=17512691</guid>

					<description><![CDATA[<p>In the third artcile in a series, we are going to focus on Kotlin objects, top-level and extension functions in MockK. </p>
<p>The post <a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>This tutorial is a great example of why MockK is an excellent choice for Kotlin and how easy we can work with Kotlin features, such as the previously mentioned objects.</p>



<p>Of course, you can find the rest of the series on my blog, too:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li>MockK: Objects, Top-Level, and Extension Functions [3/5]</li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<h2 class="wp-block-heading" id="h-video-content">Video Content</h2>



<p>As always, if you prefer a video content, then please check out my latest YouTube video:</p>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FaesDHmuny_0%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /><figcaption></figcaption></figure>


<h2 class="wp-block-heading" id="h-kotlin-objects-and-mockk">Kotlin Objects and MockK</h2>



<p>Let&#8217;s start everything by explaining <strong>how to mock Kotlin objects in MockK</strong>.</p>



<p>And as you know, objects are pretty specific, so we are going to see two, different examples and approaches.</p>



<h3 class="wp-block-heading" id="h-mockkobject"><code>mockkObject</code></h3>



<p>Let&#8217;s introduce a simple example with an object:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class One {
    fun funToTest(): UUID = SomeObject.generateId()
}

object SomeObject {
    fun generateId(): UUID = UUID.randomUUID()
}</pre>



<p>It is not rocket science, right? We are going to simply test the function that should return the UUID generated by <code>SomeObject</code> function.</p>



<p>So, if we would like to mock that UUID to gain more control over the behavior, then we can use the <code>mockkObject</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class OneTest {

    private val one = One()

    @Test
    fun `should return mocked ID`() {
        val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

        mockkObject(SomeObject)
        every { SomeObject.generateId() } returns id

        val result = one.funToTest()

        assertEquals(id, result)
    }
}</pre>



<p>The above test succeeds, and we can see that we define stubbing just like with every mock.</p>



<p>Moreover, if we add <code>mockkObject</code> inside the function, it will not affect the scope of other tests:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class OneTest {

    private val one = One()

    @Test
    fun `should return mocked ID`() {
        val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

        mockkObject(SomeObject)
        every { SomeObject.generateId() } returns id

        val result = one.funToTest()

        assertEquals(id, result)
    }

    @Test
    fun `should fail returning mocked ID`() {
        val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

        val result = one.funToTest()

        assertEquals(id, result)
    }
}</pre>



<p>This time, the second test fails because <code>SomeObject</code> returns a <strong>random value.</strong></p>



<p>Additionally, if we use the <code>mockkObject</code> , but we don&#8217;t provide stubbing, <strong>MockK will not throw any exception:</strong></p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should fail returning mocked ID`() {
    val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

    mockkObject(SomeObject)
    val result = one.funToTest()

    assertEquals(id, result)
}</pre>



<p>The above test runs just like <code>mockkObject(SomeObject)</code> does not exist. As a result, we get a random UUID.</p>



<p>So, we must be cautious about that.</p>



<h3 class="wp-block-heading"><code>unmockkObject</code></h3>



<p>Although I highly doubt we should ever use that, MockK allows us to &#8220;unmock&#8221; the object with <code>unmockkObject</code> function.</p>



<p>How does it work?</p>



<p>Let&#8217;s analyze the below snippet:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should illustrate unmockkObject`() {
    val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

    mockkObject(SomeObject)
    every { SomeObject.generateId() } returns id

    assertEquals(id, one.funToTest())

    unmockkObject(SomeObject)
    assertEquals(id, one.funToTest())
}</pre>



<p>In this example, the first assertion succeeds. However, the second <code>assertEquals</code> fails due to <code>unmockkObject</code> that reverts our mock.</p>



<p>So, again, during the second call, a random UUID is generated.</p>



<h3 class="wp-block-heading">Create Mock Object Instance</h3>



<p>I know, this title sounds simply weird.</p>



<p>Nevertheless, let&#8217;s take a look at another class- <code>Two</code> :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Two(
    private val someObject: SomeObject,
) {
    fun funToTest(): UUID = someObject.generateId()
}</pre>



<p>This time, we inject our <code>SomeObject</code> through the constructor.</p>



<p>And for consistency, in MockK, we can mock that just like a simple class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class TwoTest {

    private val someObject = mockk&lt;SomeObject>()
    private val two = Two(someObject)

    @Test
    fun `should return mocked ID`() {
        val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

        every { someObject.generateId() } returns id

        val result = two.funToTest()

        assertEquals(id, result)
    }
}</pre>



<p>But, <strong>we must remember about two, important things in this case.</strong></p>



<p>Firstly, we <strong>must provide a stubbing</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should fail due to missing stubbing`() {
    val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

    val result = two.funToTest()

    assertEquals(id, result)
}</pre>



<p>So, just like with classes, the above test fails due to missing stubbing!</p>



<p>Secondly, when defining stubbing, we <strong>must use the instance</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should fail due to incorrect stubbing`() {
    val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

    every { SomeObject.generateId() } returns id

    val result = two.funToTest()

    assertEquals(id, result)
}</pre>



<p>As we can see, we cannot refer to the <code>SomeObject</code> anymore.</p>



<p>So, as always, the choice is up to you. 🙂</p>



<h2 class="wp-block-heading">MockK and Top-Level Functions</h2>



<p>With all of that said about objects, let&#8217;s take a look at how we can deal with another Kotlin feature, <strong>top-level functions</strong>, in MockK.</p>



<p>As the first step, let&#8217;s take a look at the code to test:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Three {
    fun funToTest(): UUID = generateId()
}

fun generateId(): UUID = UUID.randomUUID()</pre>



<p>This time, instead of the object and its function, we&#8217;re dealing with top-level <code>generateId</code> .</p>



<p>And from the MockK perspective, everything looks pretty much the same as with objects:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class ThreeTest {

    private val three = Three()

    @Test
    fun `should return mocked ID`() {
        val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

        mockkStatic(::generateId)
        every { generateId() } returns id

        val result = three.funToTest()

        assertEquals(id, result)
    }
}</pre>



<p>As we can see, we use the <code>mockkStatic</code> and we simply provide our stubbing.</p>



<p>And just like in the first approach in objects, nothing happens if we define the <code>mockkStatic</code> , but we don&#8217;t set the stubbing. The random UUID is generated:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should fail due to missing stubbing`() {
    val id = UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

    mockkStatic(::generateId)

    val result = three.funToTest()

    assertEquals(id, result)
}</pre>



<p>Lastly, I just wanted to mention that we have a similar function- <code>clearStaticMockk</code>&#8211; on the table, too😉</p>



<h2 class="wp-block-heading">Extension Functions Support</h2>



<p>As the last thing in this article, let&#8217;s take a look at the example leveraging the extension function:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class Four {
    fun funToTest(): String = "abc".withCustomCase()
}

fun String.withCustomCase(): String = this.uppercase()</pre>



<p>It does not make too much sense, but we can clearly see that our extension function should return an uppercase String value.</p>



<p>And to mock this case in MockK, we can use <code>mockkStatic</code> once again:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class FourTest {

    private val four = Four()

    @Test
    fun `should return codersee`() {
        mockkStatic(String::withCustomCase)
        every { "abc".withCustomCase() } returns "codersee"
        every { "xyz".withCustomCase() } returns "not-codersee"

        val result = four.funToTest()

        assertEquals("codersee", result)
    }
}</pre>



<p>The really interesting part in the above snippet is that the String value <strong>must match!</strong></p>



<p>Additionally, MockK allows us to mock extension functions defined in a class.</p>



<p>Nevertheless, in my opinion this case is so rare, that I will skip it. And if you really need to check it, then take a look at the documentation <a href="https://mockk.io/#extension-functions" target="_blank" rel="noreferrer noopener">here</a>.</p>



<h2 class="wp-block-heading">Summary</h2>



<p>That&#8217;s all for the third article, in which we learned how to deal with Kotlin objects, top-level and extension functions in MockK.</p>



<p>Great job, and without any further ado, let&#8217;s head to the next lesson:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li>MockK: Objects, Top-Level, and Extension Functions [3/5]</li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>
<p>The post <a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/mockk-objects-top-level-extension-functions/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Verification in MockK [2/5]</title>
		<link>https://blog.codersee.com/verification-mockk/</link>
					<comments>https://blog.codersee.com/verification-mockk/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 04 Mar 2025 17:55:20 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MockK]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=17512671</guid>

					<description><![CDATA[<p>In the second article in a MockK Kotlin series, we are going to learn more about various verification techniques.</p>
<p>The post <a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>To be more specific, we are going to work with both <em>verification</em> and <em>capturing</em>&#8211; MockK Kotlin features, allowing us to perform assertions against our mocks.</p>



<p>To view other articles in this series, please take a look at:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li>Verification in MockK [2/5]</li>



<li><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level and Extension Functions [3/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<h2 class="wp-block-heading" id="h-video-content">Video Content</h2>



<p>As always, if you prefer a video content, then please check out my latest YouTube video:</p>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><a href="https://blog.codersee.com/verification-mockk/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FTVponpWSKGE%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /><figcaption></figcaption></figure>


<h2 class="wp-block-heading" id="h-why-do-we-need-verification">Why Do We Need Verification?</h2>



<p>At this point, you may wonder why we need to do anything else besides what we did previously. We configured mocks, and they worked; we made the necessary assertions. </p>



<p>Then what is the point of anything else?</p>



<p>Well, our logic is pretty clear and <strong>predictable</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun createUser(email: String, password: String): UUID {
    userRepository.findUserByEmail(email)
        ?.let { throw IllegalArgumentException("User with email $email already exists") }

    return userRepository.saveUser(email, password)
        .also { userId ->
            emailService.sendEmail(
                to = email,
                subject = "Welcome to Codersee!",
                body = "Welcome user: $userId."
            )
        }
}</pre>



<p>And by predictable, I mean that we see that every function will be invoked at most 1 time. That no other functions are invoked when we throw the exception. And I do not see any possibility that <code>saveUser</code> somehow would trigger before <code>findUserByEmail</code>.</p>



<p>But sometimes, that&#8217;s not the case.</p>



<p>Sometimes mocks may be invoked a variable number of times depending on some response, right? For example, when we call some user endpoint, we get a list of users, and then we fetch something for each user. </p>



<p>Another time, the order may be affected by the algorithm. And yet another time, it may be simply a spaghetti you inherited from someone else😉</p>



<p>And in a moment, we will learn what exactly we can do in our tests.</p>



<h2 class="wp-block-heading">Verification with <code>eq</code></h2>



<p>Before we head to the actual functions, let me share a first MockK verification tip: <strong>prefer <code>eq</code> matchers wherever possible.</strong></p>



<p>To better visualize, let&#8217;s recap the test example once again:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should throw IllegalArgumentException when user with given e-mail already exists`() {
    val email = "contact@codersee.com"
    val password = "pwd"

    val foundUser = User(UUID.randomUUID(), email, password)
    every { userRepository.findUserByEmail(email) } returns foundUser

    assertThrows&lt;IllegalArgumentException> {
        service.createUser(email, password)
    }
}</pre>



<p>We clearly see that <code>foundUser</code> will be returned only if the <code>findUserByEmail</code> is invoked with <code>contact@codersee.com</code></p>



<p>And this is already a kind of verification. Because if we would use <code>any()</code> , or <code>any&lt;String&gt;()</code> , the test would still pass. However,<strong> it would pass even if our logic sent a password there by mistake!</strong></p>



<p>So I guess you see my point here. For such cases, I would go for <code>eq</code> matcher.</p>



<h2 class="wp-block-heading">Various MockK Verifications</h2>



<p>And with all of that said, we can finally take a look at various, actual verifications in MockK.</p>



<p>For that purpose, let&#8217;s introduce a more dummy example that will help us to focus on the topic without unwanted code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class A (
    private val b: B,
    private val c: C
) {
    fun funToTest(): Int {
        return 5
    }
}

class B {
    fun funFromB(): Int = 10
}

class C {
    fun funFromC(): String = "Hi!"
}</pre>



<h3 class="wp-block-heading"><code>verify</code></h3>



<p>Let&#8217;s start with the simplest one- <code>verify</code> .</p>



<p>And for that, let&#8217;s update the <code>funToTest</code> and write a simple test for it:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun funToTest(): Int {
    repeat(10) { b.funFromB() }
    repeat(5) { c.funFromC() }
    return 5
}

@Test
fun `should return 5 without any verification`() {
    every { b.funFromB() } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)
}</pre>



<p>When we run the test, it succeeds. Moreover, we can clearly see that we can define stubbing once. Even though functions are invoked multiple times.</p>



<p>With the <code>verify</code> , we can make sure that they were invoked a specific number of times:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 5 with verification and confirmation`() {
    every { b.funFromB() } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verify(exactly = 10) { b.funFromB() }
    verify(atLeast = 5) { c.funFromC() }

    confirmVerified(b, c)
}</pre>



<p>We can use <code>exactly</code> , <code>atLeast</code> , <code>atMost</code> &#8211; the choice is up to you.</p>



<p>Additionally, if we would like to set some arbitraty <strong>timeout</strong>, then this is our go-to function.</p>



<h3 class="wp-block-heading"><code>confirmVerified</code></h3>



<p>Moreover, we should use <code>verify</code> in combination with <code>confirmVerified</code> .</p>



<p>This way, we additionally check if our test code verified all invoked functions.</p>



<p>If we get rid of <code>verify(atLeast = 5) { c.funFromC() }</code> and rerun the test, we will see:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">Verification acknowledgment failed

Verified call count: 0
Recorded call count: 5


Not verified calls:
1) C(#2).funFromC()
2) C(#2).funFromC()
3) C(#2).funFromC()
4) C(#2).funFromC()
5) C(#2).funFromC()</pre>



<p>So, as we can see, this is a great way to double-check our test assumptions (testing a test?🙂).</p>



<h3 class="wp-block-heading"><code>checkUnnecessaryStub</code></h3>



<p>Speaking of testing the test- we can additionally check if there are no unused stubbings.</p>



<p>For that purpose, let&#8217;s slightly update the example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class A(
    private val b: B,
    private val c: C
) {
    fun funToTest(): Int {
        repeat(10) { b.funFromB(7) }
        repeat(5) { c.funFromC() }
        return 5
    }
}

class B {
    fun funFromB(some: Int): Int = 10
}

class C {
    fun funFromC(): String = "Hi!"
}</pre>



<p>So this time, <code>funFromB</code> will always be invoked with <code>7</code> .</p>



<p>And if we make our test this way:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 5 with verification and confirmation`() {
    every { b.funFromB(7) } returns 1
    every { b.funFromB(6) } returns 2 // unwanted
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verify(exactly = 10) { b.funFromB(7) }
    verify(atLeast = 5) { c.funFromC() }

    confirmVerified(b, c)
    checkUnnecessaryStub(b, c)
}</pre>



<p>Then MockK will be complaining a bit:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">1) B(#1).funFromB(eq(6)))
java.lang.AssertionError: Unnecessary stubbings detected.
Following stubbings are not used, either because there are unnecessary or because tested code doesn't call them :

1) B(#1).funFromB(eq(6)))</pre>



<h3 class="wp-block-heading"><code>verifyCount</code></h3>



<p>When it comes to counts, we can use the <code>verifyCount</code> function instead:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 5 with verifyCount`() {
    every { b.funFromB(7) } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verifyCount {
        10 * { b.funFromB(7) }
        (4..5) * { c.funFromC() }
    }
    confirmVerified(b, c)
}</pre>



<p>This allows us to achieve an even cleaner test with beautiful Kotlin DSL.</p>



<p>Nevertheless, we still have to invoke <code>confirmVerified</code> separately.</p>



<h3 class="wp-block-heading"><code>verifyAll/verifyOrder/verifySequence</code></h3>



<p>Sometimes, we can use <code>verifyAll</code> , <code>verifyOrder</code> , and <code>verifySequence</code> to make the code slightly cleaner.</p>



<p>The <code>verifyAll</code> checks if all calls happened, but it does not verify the order:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 5 with verifyAll`() {
    every { b.funFromB(7) } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verifyAll {
        c.funFromC()
        b.funFromB(7)
    }
}</pre>



<p>So, the above function will work like a charm.</p>



<p>On the other hand, if we use the <code>verifyOrder</code> , it won&#8217;t work anymore, and we will have to provide a valid order:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 5 with verifyOrder`() {
    every { b.funFromB(7) } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verifyOrder {
        b.funFromB(7)
        c.funFromC()
    }
}</pre>



<p>Lastly, the <code>verifySequence</code> will work similar to <code>verifyOrder</code> , but it will force us to provide the right amount of times in the right order.</p>



<p>So, to make the test work, we would need to do a small tweak:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 5 with verifySequence`() {
    every { b.funFromB(7) } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verifySequence {
        repeat(10) { b.funFromB(7) }
        repeat(5) { c.funFromC() }
    }
}</pre>



<p>The important thing to mention is that if in our <code>verifyAll</code> or <code>verifySequence</code> block we covered all mocks, then we don&#8217;t need to add <code>confirmVerified</code> .</p>



<p>But, <strong>unfortunately</strong>, this will succeed:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should fail due to missing verification`() {
    every { b.funFromB(7) } returns 1
    every { c.funFromC() } returns ""

    val result = a.funToTest()

    assertEquals(5, result)

    verifySequence {
        repeat(10) { b.funFromB(7) }
    }
}</pre>



<p>And we must guard ourselves with <code>confirmVerified(c)</code> .</p>



<p>However, if we do the <code>b</code> and <code>c</code> check inside. Then the <code>confirmedVerified</code> is not needed anymore.</p>



<h2 class="wp-block-heading">MockK capturing</h2>



<p>Lastly, I would like to show you one more interesting MockK feature useful in verification- the <strong>capturing</strong>.</p>



<p>Let&#8217;s imagine a new function inside the <code>B</code> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class B {
    fun anotherFunFromB(some: Int) {}
}</pre>



<p>Now, the <code>anotherFunToTest</code> invokes it using the random value:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">fun anotherFunToTest(): Int {
    b.anotherFunFromB(Random.nextInt())
    return 3
}</pre>



<p>So, if we write a test this way:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 3`() {
    justRun { b.anotherFunFromB(any()) }

    val result = a.anotherFunToTest()

    assertEquals(3, result)
}</pre>



<p>We clearly see, that we cannot access this value in any way, right? It is not returned from the function itself. We cannot control it with other mock, too.</p>



<p>Thankfully, we can introduce a <strong>slot </strong>and capture the value on the fly:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 3`() {
    val randomSlot = slot&lt;Int>()

    justRun { b.anotherFunFromB(capture(randomSlot)) }

    val result = a.anotherFunToTest()

    println("Random value: ${randomSlot.captured}")
    assertEquals(3, result)
}</pre>



<p>This way, the stubbing works just like <code>any()</code> ,but additionally, we can access the random value with <code>captured</code> .</p>



<p>And although this may not be a clear verification, in some cases, it can be really helpful.</p>



<h3 class="wp-block-heading">Summary</h3>



<p>That&#8217;s all for this article about verification in MockK.</p>



<p>We covered various approaches, techniques, and at this point I am pretty sure you will be able to pick the right one for your test cases.</p>



<p>Without any further ado, let&#8217;s head to the next article in this series:</p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a></li>



<li>Verification in MockK [2/5]</li>



<li><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<p></p>
<p>The post <a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/verification-mockk/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Getting Started with MockK in Kotlin [1/5]</title>
		<link>https://blog.codersee.com/getting-started-with-mockk-kotlin/</link>
					<comments>https://blog.codersee.com/getting-started-with-mockk-kotlin/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 04 Mar 2025 17:55:01 +0000</pubDate>
				<category><![CDATA[Kotlin]]></category>
		<category><![CDATA[MockK]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=17512637</guid>

					<description><![CDATA[<p>In this, first article in a series dedicated to MockK and Kotlin, we will learn how to create mocks, define stubbings and utilize matchers.</p>
<p>The post <a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Before we head there, we will take a quick look at what exactly mocking is, and the differences between several terms that often lead to confusion. Thanks to that, we will have a solid foundation before diving into the <strong>MockK and Kotlin </strong>topics.</p>



<ul class="wp-block-list">
<li>Getting Started with MockK in Kotlin [1/5]</li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>If you enjoy this content, then check out my <a href="https://codersee.com/courses/ktor-server-pro/">Ktor Server PRO</a> course- the most comprehensive Ktor guide in the market. You&#8217;re gonna love it! 🙂 </p>
</blockquote>



<h2 class="wp-block-heading" id="h-video-content">Video Content</h2>



<p>As always, if you prefer a video content, then please check out my latest YouTube video:</p>


<figure class="wp-block-embed-youtube wp-block-embed is-type-video is-provider-youtube wp-embed-aspect-16-9 wp-has-aspect-ratio"><a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2F4prbIk2TuX4%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /><figcaption></figcaption></figure>


<h2 class="wp-block-heading" id="h-why-do-we-need-mocking">Why Do We Need Mocking?</h2>



<p>Long story short, we need mocking to isolate the unit / the system under test.</p>



<p>Sounds confusing? No worries.</p>



<p>Let&#8217;s take a look at the typical example of a function:</p>



<figure class="wp-block-image size-large"><img fetchpriority="high" decoding="async" width="1024" height="576" src="http://blog.codersee.com/wp-content/uploads/2025/03/mocking_mockk_system_under_test_dependent_on_component-1024x576.png" alt="Image is an explainer for MockK and presents a visualization of system under test / unit and dependend on components" class="wp-image-17512639" srcset="https://blog.codersee.com/wp-content/uploads/2025/03/mocking_mockk_system_under_test_dependent_on_component-1024x576.png 1024w, https://blog.codersee.com/wp-content/uploads/2025/03/mocking_mockk_system_under_test_dependent_on_component-300x169.png 300w, https://blog.codersee.com/wp-content/uploads/2025/03/mocking_mockk_system_under_test_dependent_on_component-768x432.png 768w, https://blog.codersee.com/wp-content/uploads/2025/03/mocking_mockk_system_under_test_dependent_on_component-1536x864.png 1536w, https://blog.codersee.com/wp-content/uploads/2025/03/mocking_mockk_system_under_test_dependent_on_component.png 1920w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>So, our function A- the one we would like to focus on in our test- calls both B and C. It can happen sequentially or simultaneously; it doesn&#8217;t matter.</p>



<p>What matters is that when we want to test A, we want to see its behavior in different cases. How does it behave when B returns (for instance) user data successfully? What happens in case of a null value? Does it handle exceptions gracefully?</p>



<p>And to avoid spending countless hours on manual setup, we use the <strong>mocking </strong>technique to simulate different scenarios. Mostly with the help of libraries, like MockK.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>The important thing to remember is that mocking is not limited to functions. A, B, and C may as well represent services.</p>



<p>And in various sources, A will be referred to as the System Under Test (SUT), whereas B, and C will be Depended On Component (DOC).</p>
</blockquote>



<h2 class="wp-block-heading" id="h-mocking-stubbing-test-doubles">Mocking, Stubbing, Test Doubles</h2>



<p>Frankly, please skip this section if this is your first time with mocking or MockK. I truly believe you will benefit more from focusing on learning MockK-related concepts than slight differences in wording.</p>



<p>Anyway, from the chronicler&#8217;s duty, let me illustrate a few concepts:</p>



<ul class="wp-block-list">
<li><strong>stub </strong>is a fake object that returns hard-coded answers. Typically, we use it to return some value, but we don&#8217;t care about additional info, like how many times it was invoked, etc.</li>



<li><strong>mock</strong> is pretty similar, but this time, we can verify interactions, too. For example, to see if this was invoked with a particular ID value, exactly N times.</li>



<li><strong>stubbing</strong> means setting up a <em>stub</em> or a <em>mock</em> so that a particular method returns some value or throws an exception</li>



<li><strong>mocking</strong> means creating/using a <em>mock</em></li>



<li>and lastly, we use the <strong>test doubles </strong>term for any kind of replacement we use in place of a real object in your tests (that terms comes stund doubles in movies).</li>
</ul>



<p>And if you are looking for a really deep dive, I invite you to <a href="https://martinfowler.com/articles/mocksArentStubs.html" target="_blank" rel="noreferrer noopener">Martin Fowler&#8217;s article</a>.</p>



<h2 class="wp-block-heading" id="h-mockk-imports">MockK Imports</h2>



<p>With all of that said, let&#8217;s head to the practice part. </p>



<p>Firstly, let&#8217;s define the necessary imports for MockK.</p>



<p>We will be working with a plain Kotlin / Gradle project with JUnit 5, so our <code>build.gradle.kts</code> dependencies should look as follows:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">dependencies {
    testImplementation("io.mockk:mockk:1.13.17")
    testImplementation(kotlin("test"))
}

tasks.test {
    useJUnitPlatform()
}</pre>



<p>The <code>io.mockk:mockk</code> is the only thing we need when working with MockK (unless we want to work with couroutines- but I will get back to that in the fifth lesson).</p>



<h2 class="wp-block-heading" id="h-tested-code">Tested Code</h2>



<p>Then, let&#8217;s take a look at the code we are supposed to test:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class User(val id: UUID, val email: String, val passwordHash: String)

class UserRepository {
    fun saveUser(email: String, passwordHash: String): UUID =
        UUID.fromString("aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa")

    fun findUserByEmail(email: String): User? =
        User(
            id = UUID.fromString("bbbbbbbb-bbbb-bbbb-bbbb-bbbbbbbbbbbb"),
            email = "found@codersee.com",
            passwordHash = "foundPwd"
        )
}

class EmailService {
    fun sendEmail(to: String, subject: String, body: String) {
        println("Sending body $body to $to with subject $subject")
    }
}

class UserService(
    private val userRepository: UserRepository,
    private val emailService: EmailService,
) {

    fun createUser(email: String, password: String): UUID {
        userRepository.findUserByEmail(email)
            ?.let { throw IllegalArgumentException("User with email $email already exists") }

        return userRepository.saveUser(email, password)
            .also { userId ->
                emailService.sendEmail(
                    to = email,
                    subject = "Welcome to Codersee!",
                    body = "Welcome user: $userId."
                )
            }
    }
}</pre>



<p>As we can see, we have a simple example of a <code>UserService</code> with one function- <code>createUser</code> . The service and the function that we will focus on in our tests.</p>



<p>And although <code>UserRepository</code> and <code>EmailService</code> look pretty weird, the <code>createUser</code> is more or less something we can find in our real-life code. We check if the given <code>email</code> is taken, and if that&#8217;s the case, we throw an exception. Otherwise, we save the user and send a notification e-mail.</p>



<h2 class="wp-block-heading" id="h-positive-amp-negative-scenario">Positive &amp; Negative Scenario</h2>



<p>Following, let&#8217;s do something different compared to other content about MockK. Let&#8217;s start by taking a look at the final result, and then we will see how we can get there.</p>



<p>So, firstly, let&#8217;s add the negative scenario:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class AwesomeMockkTest {

    private val userRepository: UserRepository = mockk()
    private val emailService = mockk&lt;EmailService>()

    private val service = UserService(userRepository, emailService)

    @Test
    fun `should throw IllegalArgumentException when user with given e-mail already exists`() {
        val email = "contact@codersee.com"
        val password = "pwd"

        val foundUser = User(UUID.randomUUID(), email, password)
        every { userRepository.findUserByEmail(email) } returns foundUser

        assertThrows&lt;IllegalArgumentException> {
            service.createUser(email, password)
        }

        verifyAll { userRepository.findUserByEmail(email) }
    }
}</pre>



<p>As we can see, we start all by defining dependencies for <code>UserService</code> as MockK mocks, and then we simply inject them through the constructor.</p>



<p>After that, we add our JUnit 5 test that asserts if the <code>createUser</code> function has thrown an exception, nothing unusual. The &#8220;unusual&#8221; part here is the <em>every</em> and <em>verifyAll</em> &#8211; those two blocks come from MockK, and we will get back to them in a moment.</p>



<p>With that done, let&#8217;s add one more test:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return UUID when user with given e-mail successfully created`() {
    val email = "contact@codersee.com"
    val password = "pwd"
    val createdUserUUID = UUID.randomUUID()

    every { userRepository.findUserByEmail(email) } returns null
    every { userRepository.saveUser(email, password) } returns createdUserUUID
    every {
        emailService.sendEmail(
            to = email,
            subject = "Welcome to Codersee!",
            body = "Welcome user: $createdUserUUID."
        )
    } just runs

    val result = service.createUser(email, password)

    assertEquals(createdUserUUID, result)

    verifyAll {
        userRepository.findUserByEmail(email)
        userRepository.saveUser(email, password)
        emailService.sendEmail(
            to = email,
            subject = "Welcome to Codersee!",
            body = "Welcome user: $createdUserUUID."
        )
    }
}</pre>



<p>This time, we test the positive scenario, in which the user was not found by the <code>e-mail</code> and was created successfully.</p>



<h2 class="wp-block-heading">Defining MockK Mocks</h2>



<p>With all of that done, let&#8217;s start breaking down things here.</p>



<p>Let&#8217;s take a look at what we did first:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private val userRepository: UserRepository = mockk()
private val emailService = mockk&lt;EmailService>()

private val service = UserService(userRepository, emailService)</pre>



<p>So, one of the approaches to define objects as <strong>mocks</strong> with MockK is by using the <code>mockk</code> function. </p>



<p>It is a generic function. So that&#8217;s why I presented both ways to invoke it. But please treat that as an example. In real life, I suggest you stick to either <code>mockk()</code> or <code>mockk&lt;EmailService&gt;()</code> for a cleaner code.</p>



<p>Alternatively, we can achieve exactly the same with MockK annotations:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ExtendWith(MockKExtension::class)
class AwesomeMockkTest {

  @MockK
  lateinit var userRepository: UserRepository

  @MockK
  lateinit var emailService: EmailService

  @InjectMockKs
  lateinit var service: UserService

}</pre>



<p>The preferred approach is totally up to you. The important thing to mention is that the <code>@ExtendWith(MockKExtension::class)</code> comes from <strong>JUnit 5</strong>.</p>



<p>And for the <strong>JUnit 4</strong>, we would implement a rule:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class AwesomeMockkTest {
  @get:Rule
  val mockkRule = MockKRule(this)

  @MockK
  lateinit var userRepository: UserRepository

  @MockK
  lateinit var emailService: EmailService

  @InjectMockKs
  lateinit var service: UserService

}</pre>



<h2 class="wp-block-heading">Missing Stubbing</h2>



<p>At this point, we know that we don&#8217;t use real objects, but mocks.</p>



<p>Let&#8217;s try to run our test without defining any behavior:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should throw IllegalArgumentException when user with given e-mail already exists`() {
    val email = "contact@codersee.com"
    val password = "pwd"

    assertThrows&lt;IllegalArgumentException> {
        service.createUser(email, password)
    }

    verifyAll { userRepository.findUserByEmail(email) }
}</pre>



<p>In the console log, we should see the following:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Unexpected exception type thrown, expected: &lt;java.lang.IllegalArgumentException&gt; but was: &lt;io.mockk.MockKException&gt;</p>



<p>Expected :class java.lang.IllegalArgumentException</p>



<p>Actual :class io.mockk.MockKException</p>
</blockquote>



<p>Well, the issue is that when we do not specify a stubbing for a function that was invoked, MockK <strong>throws an exception</strong>.</p>



<p>But our test logic looks already for exception, so that&#8217;s why we got a message that this is simply an unexpected one.</p>



<p>Without the <code>assertThrows</code> , the message would be more obvious:</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>no answer found for UserRepository(#1).findUserByEmail(contact@codersee.com) among the configured answers: (UserRepository(#1).saveUser(eq(contact@codersee.com), eq(pwd))))</p>



<p>io.mockk.MockKException: no answer found for UserRepository(#1).findUserByEmail(contact@codersee.com) among the configured answers: (UserRepository(#1).saveUser(eq(contact@codersee.com), eq(pwd))))</p>
</blockquote>



<p>So, <strong>lesson one</strong>: whenever we see a similar message, it means that our mock function was invoked, but we haven&#8217;t defined any stubbing.</p>



<h2 class="wp-block-heading" id="h-stubbing-in-mockk">Stubbing in MockK</h2>



<p>And we already saw how we can define a stubbing, but let&#8217;s take a look once again:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">val foundUser = User(UUID.randomUUID(), email, password)
every { userRepository.findUserByEmail(email) } returns foundUser</pre>



<p>We can read the above function as &#8220;return <code>foundUser</code> every time the <code>findUserByEmail</code> function is invoked with this, specific email value&#8221;.</p>



<p>When we run the test now, everything is working fine. Because in our logic, if the <code>findUserByEmail</code> returns a not null value, an exception is thrown. So, no more functions are invoked. In other words, <strong>no more interactions with our mock</strong> object😉 Also, our email value matches.</p>



<p>And most of the time, this is how I would suggest defining stubbing. This way, we also make sure that the exact value of <code>email</code> is passed.</p>



<p>When it comes to the answer part, <code>returns foundUser</code>, we can also use alternatives, like:</p>



<ul class="wp-block-list">
<li><code>answers { code }</code> &#8211; to define a block of code to run (and/or return a value)</li>



<li><code>throws ex</code> &#8211; to throw exception</li>



<li>and many, many more (I will put a link to the docs at the end of this article)</li>
</ul>



<h2 class="wp-block-heading">MockK Matchers</h2>



<p>The above stubbing expects that the <code>email</code> value will be equal to what we define.</p>



<p>Technically, it is the equivalent of using the <code>eq</code> function:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> every { userRepository.findUserByEmail(eq(email)) } returns foundUser</pre>



<p>And <code>eq</code> uses the <code>deepEquals</code> function to compare the values.</p>



<p>But sometimes, we do not want to, or we cannot define the exact value to match.</p>



<p>Let&#8217;s imagine that some function is invoked 20 times with various values. Technically, we could define all 20 matches.</p>



<p>But instead, we use one of the many matchers available in MockK, like <code>any</code> :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group=""> every { userRepository.findUserByEmail(any()) } returns foundUser</pre>



<p>And whereas <code>eq</code> is the most concrete one, <code>any</code> is the most generic one. The <code>foundUser</code> is returned if <code>findUserByEmail</code> is invoked with anything.</p>



<p>And MockK comes with plenty of other matchers, like:</p>



<ul class="wp-block-list">
<li><code>any(Class)</code> &#8211; to match only if an instance of a given Class is passed</li>



<li><code>isNull</code> / <code>isNull(inverse=true)</code> &#8211; for null check</li>



<li><code>cmpEq(value)</code> , <code>more(value)</code> , <code>less(value)</code> &#8211; for the <code>compareTo</code> comparisons</li>



<li>and many more that you can find in the documentation</li>
</ul>



<p>For example, let&#8217;s take a look at the <code>match</code> example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">every {
  userRepository.findUserByEmail(
    match { it.contains("@") }
  )
} returns foundUser</pre>



<p>As we can see, this way the <code>foundUser</code> will be returned only if the passed value contains <code>@</code> sign.</p>



<h2 class="wp-block-heading">Unit Functions</h2>



<p>At this point, we know how to deal with matchers and the <code>returns</code> .</p>



<p>But what if the function does not return anything? We saw that previously, so let&#8217;s take a look once again:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">every { emailService.sendEmail(any(), any(), any()) } just runs</pre>



<p>Matchers are irrelevant right now, so I replaced them with <code>any()</code> .</p>



<p>The important thing here is that <code>just runs</code> is one of the approaches.</p>



<p>Alternatively, we can achieve the same:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">every { emailService.sendEmail(any(), any(), any()) } returns Unit
every { emailService.sendEmail(any(), any(), any()) } answers { }
justRun { emailService.sendEmail(any(), any(), any()) } </pre>



<p>The choice here is totally up to you.</p>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And that&#8217;s all for our first lesson dedicated to MockK and Kotlin. </p>



<p>As I mentioned above, <a href="https://mockk.io/" target="_blank" rel="noreferrer noopener">right here</a> you can find the MockK documentation. And although I strongly encourage you to visit it, I also would suggest doing it after my series- when we cover the most important concepts:</p>



<ul class="wp-block-list">
<li>Getting Started with MockK in Kotlin [1/5]</li>



<li><a href="https://blog.codersee.com/verification-mockk/">Verification in MockK [2/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-objects-top-level-extension-functions/">MockK: Objects, Top-Level, and Extension Functions [3/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-spy-relaxed-mock-partial-mocking/">MockK: Spies, Relaxed Mocks, and Partial Mocking [4/5]</a></li>



<li><a href="https://blog.codersee.com/mockk-coroutines/">MockK with Coroutines [5/5]</a></li>
</ul>



<p></p>
<p>The post <a href="https://blog.codersee.com/getting-started-with-mockk-kotlin/">Getting Started with MockK in Kotlin [1/5]</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/getting-started-with-mockk-kotlin/feed/</wfw:commentRss>
			<slash:comments>3</slash:comments>
		
		
			</item>
		<item>
		<title>Test Spring Boot AWS S3 with Localstack and Testcontainers</title>
		<link>https://blog.codersee.com/test-spring-boot-aws-s3-with-localstack-and-testcontainers/</link>
					<comments>https://blog.codersee.com/test-spring-boot-aws-s3-with-localstack-and-testcontainers/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 24 Sep 2024 05:00:00 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[LocalStack]]></category>
		<category><![CDATA[S3 Object Storage]]></category>
		<category><![CDATA[Testcontainers]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=12009164</guid>

					<description><![CDATA[<p>The last article in a series dedicated to Spring Boot AWS S3 integration focused on testing with LocalStack and Testcontainers.</p>
<p>The post <a href="https://blog.codersee.com/test-spring-boot-aws-s3-with-localstack-and-testcontainers/">Test Spring Boot AWS S3 with Localstack and Testcontainers</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Welcome to the <strong>last article</strong> in a series dedicated to integrating a Spring Boot Kotlin app with <strong>AWS S3</strong> Object Storage, in which we will focus on <strong>integration testing with LocalStack and Testcontainers</strong>. And although we will focus on Object Storage, the approach we will use can be easily replicated with other AWS services.</p>



<p>I can guarantee that you will benefit from this tutorial regardless of whether you saw previous articles about S3Client or S3Template, or not. But, I definitely encourage you to take a look at them, too: </p>



<ul class="wp-block-list">
<li><a href="https://blog.codersee.com/spring-boot-aws-s3-s3client-kotlin/">#1 Spring Boot with AWS S3, S3Client, and Kotlin</a></li>



<li><a href="https://blog.codersee.com/spring-boot-with-kotlin-aws-s3-and-s3template/">#2 Spring Boot with Kotlin, AWS S3, and S3Template</a></li>



<li>#3 (This article)</li>
</ul>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video that covers all three articles:</p>



<div>
<a href="https://blog.codersee.com/test-spring-boot-aws-s3-with-localstack-and-testcontainers/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FuTV9w1JehHM%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p></div>



<p>If you find this content useful,<strong> please leave a subscription</strong> 🙂</p>



<h2 class="wp-block-heading" id="h-prerequisites">Prerequisites</h2>



<p>Before heading to the guide, I just wanted to emphasize that today we will be working with <strong>Testcontainers</strong>. And this means that we must have a <strong>supported Docker environment</strong>.</p>



<p>So, if you do not have Docker configured on your local and want to follow this article, please check out <a href="https://java.testcontainers.org/supported_docker_environment/" target="_blank" rel="noreferrer noopener">their documentation</a>.</p>



<p>Of course, you must have Java, IDE, and Spring Boot project too, but I believe this is quite obvious 😉 </p>



<h2 class="wp-block-heading" id="h-testcontainers-and-localstack">Testcontainers and LocalStack</h2>



<p>Lastly, I would like to say a few words about the Testcontainers and LocalStack, which in my opinion are a great way to test Spring Boot S3 integration (and other AWS integrations, too). </p>



<h3 class="wp-block-heading" id="h-testcontainers">Testcontainers</h3>



<p><strong>Testcontainers </strong>is a library for providing throwaway, lightweight instances of Docker containers. They are an excellent approach whenever need to test behavior dependent on external services, like AWS, or some external databases. </p>



<p>Long story short, instead of mocking, or manual set up of some test environment, we define test dependencies as code. Then, we can run our test code and disposable containers will be started and deleted after they finish. </p>



<p>Let&#8217;s take a look at the example from <a href="https://docs.spring.io/spring-boot/reference/testing/testcontainers.html" target="_blank" rel="noreferrer noopener">Spring Boot docs</a>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Testcontainers
@SpringBootTest
class MyIntegrationTests {

  @Test
  fun myTest() {
    // ...
  }

  companion object {
    @Container
    @JvmStatic
    val neo4j = Neo4jContainer("neo4j:5");
  }
}</pre>



<p>The above code runs a Neo4j docker container before the tests. Of course, this is just an example, so most of the time, we will need to add some more config. </p>



<p>Nevertheless, we can clearly see that this Testcontainers JUnit integration allows us to achieve our goal in an easy and neat manner. </p>



<h3 class="wp-block-heading" id="h-localstack">Localstack </h3>



<p><strong>Localstack</strong>, on the other hand, is a cloud service emulator that runs in a single container. In other words, we can run AWS applications or Lambdas <strong>without connecting to the remote cloud provider</strong>. </p>



<p>And thanks to the Testcontainers module for LocalStack, we can test various AWS integrations with just a few lines of code. </p>



<p>Again, let&#8217;s take a look at the example, but this time from the LocalStack documentation: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">DockerImageName localstackImage = DockerImageName.parse("localstack/localstack:3.5.0");

@Rule
public LocalStackContainer localstack = new LocalStackContainer(localstackImage)
        .withServices(S3);</pre>



<p>You will find links to both documentation at the end of this article. But for now, let&#8217;s not distract ourselves and focus on what we came here for 😉</p>



<h2 class="wp-block-heading" id="h-configure-project">Configure Project</h2>



<p>If you are following my S3 series, or you already have a Spring Boot project, then those are the necessary dependencies for us today: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">testImplementation("org.springframework.boot:spring-boot-starter-webflux")
testImplementation("org.testcontainers:localstack")
testImplementation("org.springframework.boot:spring-boot-testcontainers")</pre>



<p>As we can see, apart from LocalStack and TestContainers, we must provide the Spring Boot Starter WebFlux. </p>



<p>But why? </p>



<p>Well, this is necessary to work with WebTestClient- a client we will use to test our web servers (REST endpoints). </p>



<p>On the other hand, if you would like to set up a project from scratch, then please navigate to the <a href="https://start.spring.io/" target="_blank" rel="noreferrer noopener">Spring Initializr</a> and select the following:</p>



<figure class="wp-block-image aligncenter size-large"><img decoding="async" width="1024" height="517" src="http://blog.codersee.com/wp-content/uploads/2024/09/codersee_integration_testing_spring_boot_aws_s3_spring_initializr_page-1024x517.png" alt="Image is a screenshot from Spring Initializr page and shows the settings necessary for integartion testing of Spring Boot and AWS S3 connection." class="wp-image-12009173" srcset="https://blog.codersee.com/wp-content/uploads/2024/09/codersee_integration_testing_spring_boot_aws_s3_spring_initializr_page-1024x517.png 1024w, https://blog.codersee.com/wp-content/uploads/2024/09/codersee_integration_testing_spring_boot_aws_s3_spring_initializr_page-300x151.png 300w, https://blog.codersee.com/wp-content/uploads/2024/09/codersee_integration_testing_spring_boot_aws_s3_spring_initializr_page-768x388.png 768w, https://blog.codersee.com/wp-content/uploads/2024/09/codersee_integration_testing_spring_boot_aws_s3_spring_initializr_page.png 1507w" sizes="(max-width: 1024px) 100vw, 1024px" /></figure>



<p>However, please keep in mind that LocalStack is not provided out of the box in Spring, so we must add it manually. </p>



<p>Moreover, as we have chosen the Spring Web, the WebFlux dependency is not present, too:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="generic" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">testImplementation("org.springframework.boot:spring-boot-starter-webflux")
testImplementation("org.testcontainers:localstack")</pre>



<h2 class="wp-block-heading" id="h-testcontainers-singleton-approach">Testcontainers Singleton Approach</h2>



<p>With all of that being done, let&#8217;s head to the practice part. </p>



<p>When working with Testcontainers, we can configure them in various ways: </p>



<ul class="wp-block-list">
<li>we can use the<strong> JUnit extension</strong> (Jupiter integration)- which allows us to use <em>@Testcontainers</em> and <em>@Container</em> annotations and makes JUnit responsible for the automatic startup and stop of containers in our tests.</li>



<li>we can configure them <strong>manually </strong>in every test case, </li>



<li>or, alternatively, we can use the <strong>singleton approach</strong>&#8211; in which we control containers&#8217; lifecycle <a href="https://java.testcontainers.org/test_framework_integration/manual_lifecycle_control/" target="_blank" rel="noreferrer noopener">manually</a>. But, thanks to that we can easily reuse them across multiple test classes. </li>
</ul>



<p>Of course, these are not all approaches, and based on your needs you may want to configure Testcontainers differently. Nevertheless, in this tutorial, we will focus on the <strong>manual, reusable approach</strong>.</p>



<h3 class="wp-block-heading" id="h-introduce-base-class">Introduce Base Class</h3>



<p>Firstly, let&#8217;s introduce the <code>LocalStackIntegrationTest</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@SpringBootTest(webEnvironment = RANDOM_PORT)
class LocalStackIntegrationTest { }</pre>



<p>As we can see, we mark our class with <em>@SpringBootTest</em> &#8211; annotation necessary to run our integration tests and inject the instance of WebTestClient later in our subclasses. </p>



<h3 class="wp-block-heading" id="h-add-testcontainer">Add Testcontainer</h3>



<p>Following, let&#8217;s take a look at how to instantiate a LocalStack container:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">companion object {
  val localStack: LocalStackContainer = LocalStackContainer(
    DockerImageName.parse("localstack/localstack:3.7.2")
  )
}</pre>



<p>Right here, we create an instance of <strong>LocalStackContainer</strong> and we pass the name of a Docker image &#8211; <code>localstack/localstack:3.7.2</code>&#8211; to its constructor. Alternatively, if we are working only with AWS S3 Buckets service, then we can use a dedicated image- <code>localstack:s3-latest</code>. But personally, I am not a big fan of the <strong>latest</strong> tag, which can easily break our code.</p>



<p>Additionally, we put the LocalStackContainer instance in the <strong>companion object</strong>. Why? Because in the next steps, we will reference it in a function annotated with <em>@DynamicPropertySource</em>&#8211; and it must be static.</p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>Note related to <strong>JUnit extension</strong>: </p>



<p><br>This is not the case here, as we want to take care of the container lifecycle manually, but, when using the Jupiter integration, containers declared as static fields will be shared between test methods. They will be started only once before any test method is executed and stopped after the last test method has executed. So, if in your case you pick the JUnit extension and don&#8217;t want that to happen, then you must not put the localstack in the companion object. </p>
</blockquote>



<h3 class="wp-block-heading" id="h-control-testcontainer-lifecycle">Control Testcontainer lifecycle</h3>



<p>As we already know, with this approach <strong>we are responsible</strong> for the container lifecycle control. And although this may sound complicated, it basically means that without the extension we must start the container manually.</p>



<p>So the companion object after the update will look, as follows:  </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">companion object {
  val localStack: LocalStackContainer = LocalStackContainer(
    DockerImageName.parse("localstack/localstack:3.7.2")
  ).apply {
    start()
  }
}</pre>



<p>Basically, we use the Kotlin scope function (you can learn more about it in my <a href="https://codersee.com/the-complete-kotlin-course/">Kotlin course</a>) to invoke the <code>start()</code> function on the <code>localStack</code> instance. And as the name suggests, this function will start the container (and pull the image, if necessary).</p>



<p>And basically,<strong> that is all we need to do here.</strong> With the above code, the container will be started when the base class is loaded and shared across all inheriting test classes. </p>



<p>Of course, there is also the <code>stop()</code> function that we can invoke to kill and remove the container. </p>



<p>Nevertheless, <strong>we do not have to do it</strong>. Why? Let&#8217;s figure out. </p>



<h3 class="wp-block-heading" id="h-ryuk">Ryuk</h3>



<p>Ryuk is a kind of &#8220;garbage collector&#8221; in Testcontainers. </p>



<p>Whenever we run integration tests, Testcontianers core starts <strong>one more container</strong>: </p>



<figure class="wp-block-image size-full"><img decoding="async" width="756" height="188" src="http://blog.codersee.com/wp-content/uploads/2024/09/image.png" alt="Image is a screenshot from Docker Desktop and presents two running container: the actual one and Ryuk started by Testcontainers core to clean up after integration testing is done." class="wp-image-12009191" srcset="https://blog.codersee.com/wp-content/uploads/2024/09/image.png 756w, https://blog.codersee.com/wp-content/uploads/2024/09/image-300x75.png 300w" sizes="(max-width: 756px) 100vw, 756px" /></figure>



<p>Long story short, this container is responsible for removing containers/networks/volumes created by our test cases. So, even if we do not clean the environment ourselves- for example with the <code>stop()</code> function- the Ryuk container will take care of that. </p>



<h3 class="wp-block-heading" id="h-test-properties-with-dynamicpropertysource">Test Properties With DynamicPropertySource</h3>



<p>With that done, we need to update our environment configuration. </p>



<p>If we try to run our Spring Boot application at this point, our logic responsible for communication with Amazon S3 will try to reach the <strong>actual AWS instance</strong>. It will use the defaults, or make use of the things we configured in the <code>application.yaml</code>. </p>



<p>And this is not what we want, right? Instead, we would like to connect to the Testcontainer LocalStack instance.  </p>



<p>In some examples, you might have seen the usage of application properties files. Nevertheless, if we want to be more flexible and make use of containers started on random ports, then the <strong>@DynamicPropertySource</strong> is our best friend here: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">companion object {
  val localStack: LocalStackContainer = LocalStackContainer(
    DockerImageName.parse("localstack/localstack:3.7.2")
  ).apply {
    start()
  }

  @JvmStatic
  @DynamicPropertySource
  fun overrideProperties(registry: DynamicPropertyRegistry) {
    registry.add("spring.cloud.aws.region.static") { localStack.region }
    registry.add("spring.cloud.aws.credentials.access-key") { localStack.accessKey }
    registry.add("spring.cloud.aws.credentials.secret-key") { localStack.secretKey }
    registry.add("spring.cloud.aws.s3.endpoint") { localStack.getEndpointOverride(S3).toString() }
  }

}</pre>



<p>Thanks to that annotation, we can dynamically provide values to our test environment <strong>based on the LocalStack instance</strong>.</p>



<p>Of course, we must remember that methods annotated with <em>@DynamicPropertySource</em> <strong>must be static</strong>! And that&#8217;s why we use it with the @JvmStatic annotation.</p>



<h2 class="wp-block-heading" id="h-utilize-localstack-aws-cli">Utilize LocalStack AWS CLI</h2>



<p>At this point, we have our base class ready, but before we head to the tests, I would like to show you the <strong>LocalStack AWS CLI</strong> and why and how to use it.  </p>



<p>As the first step, let&#8217;s create the <code>util</code> package and add the <code>LocalStackUtil.kt</code> file:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.testcontainers.containers.localstack.LocalStackContainer

fun LocalStackContainer.createBucket(bucketName: String) {
  this.execInContainer("awslocal", "s3api", "create-bucket", "--bucket", bucketName)
}

fun LocalStackContainer.deleteBucket(bucketName: String) {
  this.execInContainer("awslocal", "s3api", "delete-bucket", "--bucket", bucketName)
}

fun LocalStackContainer.deleteObject(bucketName: String, objectName: String) {
  this.execInContainer("awslocal", "s3api", "delete-object", "--bucket", bucketName, "--key", objectName)
}</pre>



<p>As we can see, we introduced 3 helper extension functions that we will later use to create and delete buckets and objects. This way, we can <strong>easily clean up</strong> between the tests (we use the shared approach, right?). Moreover, it will <strong>simplify the setup process</strong> for each test case.</p>



<p>The above code combines the <code>execInContainer</code> &#8211; which will run the passed command in our running LocalStack container, just like with the <code>docker exec</code>, and the <code>awslocal</code>&#8211; a LocalStack wrapper around the AWS CLI. So, if you&#8217;ve ever been working with the AWS command line interface, then you will see that this is 1:1. </p>



<p>Unfortunately, we must provide the command as a separate String value, because otherwise, we will end up with: </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p>OCI runtime exec failed: exec failed: container_linux.go:380: starting container process caused: exec: &#8220;awslocal s3api create-bucket &#8211;bucket bucket-1&#8221;: executable file not found in $PATH: unknown</p>
</blockquote>



<h2 class="wp-block-heading" id="h-write-integration-test-cases">Write Integration Test Cases</h2>



<p>With all of that LocalStack preparation done (I know, quite a bunch of things to learn, but once you learn this, it will be a simple copy-paste), we can finally write some integration tests for our Spring Boot S3 integration.</p>



<p>Firstly, let&#8217;s create the <code>controller</code> package and put the <code>BucketControllerIntegrationTest</code> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">class BucketControllerIntegrationTest(
  @Autowired private val webTestClient: WebTestClient
) : LocalStackIntegrationTest() { }</pre>



<p>As we can see, no annotations are required. We simply extend the <code>LocalStackIntegrationTest</code> class and inject the <code>WebTestClient</code>.</p>



<h3 class="wp-block-heading" id="h-test-no-buckets-exist">Test No Buckets Exist</h3>



<p>Nextly, let&#8217;s introduce our first test case. If we do not do anything, we expect that no buckets exist in our S3 instance: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given no existing buckets When getting list of buckets Then return an empty array`() {
  val buckets = webTestClient
    .get().uri("/buckets")
    .exchange()
    .expectStatus().isOk()
    .expectBody(object : ParameterizedTypeReference&lt;List&lt;String>>() {})
    .returnResult()
    .responseBody

  assertNotNull(buckets)
  assertTrue(buckets.isEmpty())
}</pre>



<p>As mentioned before, we use the <em>WebTestClient</em> to make a GET HTTP request to the <code>/buckets</code> endpoint. Then, we use a small hack with <code>ParameterizedTypeReference</code>&#8211; because the endpoint returns a list of Strings and we use Kotlin- and we obtain the response body. </p>



<p>Lastly, we have plain assertions. We verify that the response body is not null and that our S3 bucket list is empty.</p>



<h3 class="wp-block-heading" id="h-verify-s3-bucket-exists-in-localstack">Verify S3 Bucket Exists In LocalStack</h3>



<p>Following, let&#8217;s see our helper functions in action:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given one existing bucket When getting list of buckets Then return an array with expected bucket name`() {
  val bucketName = "bucket-1"
  localStack.createBucket(bucketName)

  val expectedJson = """
    [ "Bucket #1: $bucketName" ]
  """

  webTestClient
    .get().uri("/buckets")
    .exchange()
    .expectStatus().isOk()
    .expectBody()
    .json(expectedJson)

  localStack.deleteBucket(bucketName)
}</pre>



<p>This time, we utilize the <code>createBucket</code> and make sure that the <code>/buckets</code> endpoint returns the expected JSON. Please note that this is another way to assert the response body.   </p>



<p>After all, we delete the existing bucket, so it won&#8217;t affect other test cases.</p>



<h3 class="wp-block-heading" id="h-assert-bucket-created-successfully">Assert Bucket Created Successfully</h3>



<p>As the next step, let&#8217;s take a look at how we can check if our endpoint responsible for creating new S3 buckets works. And I see two paths we can go here.</p>



<p>The first one, using the <code>execInContainer</code>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given no existing buckets When creating bucket Then create bucket successfully`() {
  val bucketName = "bucket-2"
  
  webTestClient
    .post().uri("/buckets")
    .bodyValue(BucketRequest(bucketName = bucketName))
    .exchange()
    .expectStatus().isOk()
  
  val execResult = localStack.execInContainer("awslocal", "s3api", "list-buckets").stdout
  
  assertTrue(execResult.contains(bucketName))  
  localStack.deleteBucket(bucketName)
}</pre>



<p>The important thing to mention here is that the <code>execInContainer</code> returns the <code>ExecResult</code>. And thanks to that, we can read additional info, like <code>stdout</code>, <code>stderr</code>, or <code>exitCode</code>.</p>



<p>And thanks to the <code>stdout</code>, we can get this JSON to verify it contains particular bucket name (or even we could parse that to an object): </p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "Buckets": [
    {
      "Name": "bucket-2",
      "CreationDate": "2024-09-19T05:28:42.000Z"
    }
  ],
  "Owner": {
    "DisplayName": "webfile",
    "ID": "75aa57f09aa0c8caeab4f8c24e99d10f8e7faeebf76c078efc7c6caea54ba06a"
  }
}</pre>



<p>Alternatively, we can use the <code>/buckets</code> endpoint once again, too:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given no existing buckets When creating bucket Then create bucket successfully`() {
  val bucketName = "bucket-2"

  webTestClient
    .post().uri("/buckets")
    .bodyValue(BucketRequest(bucketName = bucketName))
    .exchange()
    .expectStatus().isOk()

  val expectedJson = """
    [ "Bucket #1: $bucketName" ]
  """
  webTestClient
    .get().uri("/buckets")
    .exchange()
    .expectStatus().isOk()
    .expectBody()
    .json(expectedJson)

  localStack.deleteBucket(bucketName)
}</pre>



<h3 class="wp-block-heading" id="h-test-remaining-cases">Test Remaining Cases</h3>



<p>The remaining cases of our integration test use a more or less similar approach, so I will simply copy-paste them here so that you can analyze them. </p>



<p>At this point, I am pretty sure you understand the general idea behind what I understand by testing of Spring Boot S3 integration with LocalStack, so I don&#8217;t see the need for explaining them one- by one:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given no objects existing in the bucket When getting objects of a bucket Then return an empty array`() {
  val bucketName = "bucket-3"
  localStack.createBucket(bucketName)

  val objects = webTestClient
    .get().uri("/buckets/$bucketName/objects")
    .exchange()
    .expectStatus().isOk()
    .expectBody(object : ParameterizedTypeReference&lt;List&lt;String>>() {})
    .returnResult()
    .responseBody

  assertNotNull(objects)
  assertTrue(objects.isEmpty())

  localStack.deleteBucket(bucketName)
}

@Test
fun `Given no objects When creating example object Then return created object`() {
  val bucketName = "bucket-4"
  val objectName = "example.json"
  localStack.createBucket(bucketName)

  val expectedJson = """
    {
      "id": "123",
      "name": "Some name"
    }
  """

  webTestClient
    .post().uri("/buckets/$bucketName/objects")
    .exchange()
    .expectStatus().isOk()
    .expectBody()
    .json(expectedJson)

  localStack.deleteObject(bucketName, objectName)
  localStack.deleteBucket(bucketName)
}

@Test
fun `Given created object When getting list of objects Then return array with one object`() {
  val bucketName = "bucket-5"
  val objectName = "example.json"
  localStack.createBucket(bucketName)

  val expectedJson = """
    [ $objectName ]
  """

  webTestClient
    .post().uri("/buckets/$bucketName/objects")
    .exchange()
    .expectStatus().isOk()

  webTestClient
    .get().uri("/buckets/$bucketName/objects")
    .exchange()
    .expectStatus().isOk()
    .expectBody()
    .json(expectedJson)

  localStack.deleteObject(bucketName, objectName)
  localStack.deleteBucket(bucketName)
}

@Test
fun `Given existing object When getting object by key Then return object content`() {
  val bucketName = "bucket-6"
  val objectName = "example.json"
  localStack.createBucket(bucketName)

  val expected = """
    {
      "id": "123",
      "name": "Some name"
    }
  """

  webTestClient
    .post().uri("/buckets/$bucketName/objects")
    .exchange()

  webTestClient
    .get().uri("/buckets/$bucketName/objects/$objectName")
    .exchange()
    .expectStatus().isOk()
    .expectBody()
    .json(expected)

  localStack.deleteObject(bucketName, objectName)
  localStack.deleteBucket(bucketName)
}

@Test
fun `Given existing bucket with object When deleting bucket Then bucket is removed`() {
  val bucketName = "bucket-7"
  localStack.createBucket(bucketName)

  webTestClient
    .post().uri("/buckets/$bucketName/objects")
    .exchange()
    .expectStatus().isOk()

  webTestClient
    .delete().uri("/buckets/$bucketName")
    .exchange()
    .expectStatus().isOk()

  val buckets = webTestClient
    .get().uri("/buckets")
    .exchange()
    .expectStatus().isOk()
    .expectBody(object : ParameterizedTypeReference&lt;List&lt;String>>() {})
    .returnResult()
    .responseBody

  assertNotNull(buckets)
  assertTrue(buckets.isEmpty())
}</pre>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And that is all for this tutorial, in which we learned how to implement <strong>integration tests </strong>for <strong>Spring Boot AWS S3 </strong>integration with <strong>LocalStack </strong>and <strong>Testcontainers.</strong></p>



<p>I hope you enjoyed it and for the source code, please visit <a href="https://github.com/codersee-blog/spring-boot-3-kotlin-aws-s3-localstack-testcontainers" target="_blank" rel="noreferrer noopener">this GitHub repository</a>. </p>



<p>Have a great day and see you in the next articles! 🙂 </p>
<p>The post <a href="https://blog.codersee.com/test-spring-boot-aws-s3-with-localstack-and-testcontainers/">Test Spring Boot AWS S3 with Localstack and Testcontainers</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/test-spring-boot-aws-s3-with-localstack-and-testcontainers/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Integration Tests for WebClient with WireMock</title>
		<link>https://blog.codersee.com/integration-tests-webclient-wiremock/</link>
					<comments>https://blog.codersee.com/integration-tests-webclient-wiremock/#comments</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Wed, 28 Feb 2024 10:56:57 +0000</pubDate>
				<category><![CDATA[Spring]]></category>
		<category><![CDATA[JUnit 5]]></category>
		<category><![CDATA[Spring Boot]]></category>
		<category><![CDATA[Testing]]></category>
		<category><![CDATA[WebClient]]></category>
		<category><![CDATA[WireMock]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9508747</guid>

					<description><![CDATA[<p>Learn how to perform integration testing for Spring WebClient that invokes external REST APIs with WireMock and JUnit 5.</p>
<p>The post <a href="https://blog.codersee.com/integration-tests-webclient-wiremock/">Integration Tests for WebClient with WireMock</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hi guys! 🙂 Today we will learn how to do <strong>integration testing</strong> for <strong>Spring WebClient</strong> that invokes external REST APIs with <strong>WireMock</strong> and <strong>JUnit 5</strong>. </p>



<p>As an example, we will implement a simple logic responsible for querying the <strong>GitHub API</strong> using coroutines. Nevertheless, I am pretty sure you will be able to easily adjust this article to your needs. (of course, if you are here only for the WireMock part, then I recommend skipping to the &#8220;WebClient Integration Testing With WireMock&#8221; chapter).</p>



<p>Lastly, I just wanted to add that you can use this testing approach regardless of whether you are using WebClient, Retrofit, Ktor Client, or any other HTTP client. </p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<a href="https://blog.codersee.com/integration-tests-webclient-wiremock/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2Fhbr4snySA6I%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p></div>



<p>If you find this content useful,<strong> please leave a subscription</strong> 🙂</p>



<h2 class="wp-block-heading" id="h-which-webclient-testing-strategy-is-the-best">Which WebClient Testing Strategy Is The Best?</h2>



<p>But before we head to the practice part, let&#8217;s try to answer the above question. </p>



<p>Quick answer- there is no such thing as <strong>the best testing strategy</strong>. </p>



<p>And for the longer answer, let&#8217;s take a look at the visualization of the testing pyramid first:</p>



<figure class="wp-block-image aligncenter size-large is-resized"><img loading="lazy" decoding="async" width="1024" height="1024" src="http://blog.codersee.com/wp-content/uploads/2024/02/tests_pyramid-1024x1024.png" alt="Image presents a diagram with testing pyramid including e2e tests, integration tests, and unit tests helping to better understand the best approach for WebClient WireMock testing. " class="wp-image-9508749" style="width:542px;height:auto" srcset="https://blog.codersee.com/wp-content/uploads/2024/02/tests_pyramid-1024x1024.png 1024w, https://blog.codersee.com/wp-content/uploads/2024/02/tests_pyramid-300x300.png 300w, https://blog.codersee.com/wp-content/uploads/2024/02/tests_pyramid-150x150.png 150w, https://blog.codersee.com/wp-content/uploads/2024/02/tests_pyramid-768x768.png 768w, https://blog.codersee.com/wp-content/uploads/2024/02/tests_pyramid.png 1080w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>The tests are ordered based on their scope and execution time. The closer we are to the top, the longer the tests take, but they also give us more confidence. </p>



<ul class="wp-block-list">
<li><strong>unit tests</strong> form the base, as they are quick to run and pinpoint specific code issues,</li>



<li><strong>integration tests</strong> come next, validating the interactions between units,</li>



<li><strong>E2E tests</strong>, with a broader scope, are placed at the top.</li>
</ul>



<p>So long story short, although the e2e tests give us the most confidence, we cannot rely only on them, because the feedback loop would take way too long. And this would affect the development process.</p>



<p>So usually, we make concessions and introduce more integration and unit tests. </p>



<p>But which of these two should we pick for the WebClient? </p>



<p>In my opinion- <strong>integration tests</strong>. </p>



<p>Whenever we are talking about logic responsible for communicating with external API, we must make sure that: </p>



<ul class="wp-block-list">
<li>we query the appropriate URL, </li>



<li>we pass the necessary headers with appropriate values, </li>



<li>request/response bodies are properly serialized/deserialized, </li>



<li>and many, many more. </li>
</ul>



<p>With unit testing, the amount of mocking here would be so significant that I would question whether we need such a test at all. </p>



<p>Moreover, in Spring we can write integration tests for WebClient with WireMock at almost no effort. </p>



<h2 class="wp-block-heading" id="h-set-up-github-api-key">Set Up GitHub API Key </h2>



<p>With that said, let&#8217;s set up the API key we will use to query the GitHub API. </p>



<blockquote class="wp-block-quote is-layout-flow wp-block-quote-is-layout-flow">
<p></p>
<cite><strong>Note:</strong> technically, the endpoint we will use does not require <strong>any token.</strong> However, for the learning purposes I want to show you how to deal with passing bearer tokens, too 🙂 </cite></blockquote>



<p>As the first step, let&#8217;s navigate to the <a href="https://github.com/settings/tokens" target="_blank" rel="noreferrer noopener">tokens tab</a> in GitHub settings and click the &#8220;Generate new token (classic)&#8221;: </p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="777" height="190" src="http://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_1.png" alt="Image is a screenshot and presents how to generate new classic GitHub token." class="wp-image-9508752" style="width:777px;height:auto" srcset="https://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_1.png 777w, https://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_1-300x73.png 300w, https://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_1-768x188.png 768w" sizes="auto, (max-width: 777px) 100vw, 777px" /></figure>



<p>On the next page, let&#8217;s specify the name, expiration, and desired scopes: </p>



<figure class="wp-block-image aligncenter size-full"><img loading="lazy" decoding="async" width="780" height="457" src="http://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_2.png" alt="Image is a screenshot from GitHub tokens page." class="wp-image-9508753" srcset="https://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_2.png 780w, https://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_2-300x176.png 300w, https://blog.codersee.com/wp-content/uploads/2024/02/github_generate_token_2-768x450.png 768w" sizes="auto, (max-width: 780px) 100vw, 780px" /></figure>



<p></p>



<p>If you don&#8217;t know what scopes you will need, please follow the principle of lowest privilege. At the end of the day, we can generate a new token at some point in the future when the requirements change.</p>



<p>When we are ready, let&#8217;s hit the generate button <strong>copy the token value</strong>, and <strong>store it securely</strong>. We will not see it again! </p>



<h2 class="wp-block-heading" id="h-query-the-api-with-webclient">Query The Api With WebClient</h2>



<p>Before we implement the WireMock tests, let&#8217;s prepare a simple project responsible for querying the external API with WebClient. So, even if you are here only for the WireMock part, I encourage you to briefly check this paragraph to be on the same page 😉 </p>



<p>Long story short, we will implement WebClient with coroutines that will query the &#8220;List repositories for a user&#8221; endpoint. For more details about it, check out the <a href="https://docs.github.com/en/rest/repos/repos?apiVersion=2022-11-28#list-repositories-for-a-user" target="_blank" rel="noreferrer noopener">GitHub API documentation</a>, please. </p>



<h3 class="wp-block-heading" id="h-generate-new-project">Generate New Project</h3>



<p>As the first step, let&#8217;s navigate to the <a href="https://start.spring.io/" target="_blank" rel="noreferrer noopener">https://start.spring.io/</a> page and generate a fresh Spring Boot project:</p>



<figure class="wp-block-image aligncenter size-large"><img loading="lazy" decoding="async" width="1024" height="530" src="http://blog.codersee.com/wp-content/uploads/2024/02/webclient_wiremock_generate_fresh_spring_boot_project-1024x530.png" alt="Image presents the Spring Initializr page screenshot of a project setting that we will use to implement WebClient logic and test with WireMock." class="wp-image-9508754" srcset="https://blog.codersee.com/wp-content/uploads/2024/02/webclient_wiremock_generate_fresh_spring_boot_project-1024x530.png 1024w, https://blog.codersee.com/wp-content/uploads/2024/02/webclient_wiremock_generate_fresh_spring_boot_project-300x155.png 300w, https://blog.codersee.com/wp-content/uploads/2024/02/webclient_wiremock_generate_fresh_spring_boot_project-768x398.png 768w, https://blog.codersee.com/wp-content/uploads/2024/02/webclient_wiremock_generate_fresh_spring_boot_project.png 1510w" sizes="auto, (max-width: 1024px) 100vw, 1024px" /></figure>



<p>In general, the most important thing is that we will use Kotlin and Spring Reactive Web this time. Versions and metadata are totally up to you. </p>



<p>Of course, let&#8217;s click the &#8220;Generate&#8221; button, download the ZIP file, and import that to our IDE. Personally, I am using IntelliJ IDEA and if you would like to learn more about its setup, then check out my video on <a href="https://www.youtube.com/watch?v=npib90rBLE4" target="_blank" rel="noreferrer noopener">how to install IntelliJ for Kotlin development</a>.</p>



<h3 class="wp-block-heading" id="h-update-application-properties">Update Application Properties</h3>



<p>As the next step, let&#8217;s navigate to the <code>resources</code> package and update the <code>application.yaml</code> file: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="yaml" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">api:
  github:
    key: ${GITHUB_API_TOKEN:123}
    url: ${GITHUB_API_BASE_URL:http://localhost:8090}
    version: ${GITHUB_API_VERSION:2022-11-28}</pre>



<p>Above we can see our custom properties. </p>



<p>We will source values for our GitHub key, URL, and version from environment variables. </p>



<p>Not only is this approach <strong>secure</strong> (hardcoding the key with token value would be the worst thing you could do), but also <strong>flexible</strong> (we can pass different values depending on the environment we are running our app in). </p>



<h3 class="wp-block-heading" id="h-webclient-configuration">WebClient Configuration</h3>



<p>Following, let&#8217;s configure a WebClient bean that we will use whenever we want to call the GitHub API. </p>



<p>Firstly, let&#8217;s add the <code>config</code> package and put the <code>GitHubApiProperties</code> data class in there:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@ConfigurationProperties("api.github")
data class GitHubApiProperties(
    val url: String,
    val key: String,
    val version: String,
)</pre>



<p>In my opinion, the <code>@ConfigurationProperties</code> annotation is the cleanest way to inject values from properties. As we can see above, the <strong>prefix</strong> and <strong>field names</strong> simply reflect the structure from the previous step. </p>



<p>With that done, let&#8217;s add the <code>GitHubApiConfig</code> in the same package: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Configuration
@EnableConfigurationProperties(GitHubApiProperties::class)
class GitHubApiConfig(
    private val gitHubApiProperties: GitHubApiProperties,
) {
    @Bean
    fun webClient(builder: WebClient.Builder): WebClient =
        builder
            .baseUrl(gitHubApiProperties.url)
            .defaultHeader("Authorization", "Bearer ${gitHubApiProperties.key}")
            .defaultHeader("X-GitHub-Api-Version", gitHubApiProperties.version)
            .defaultHeader("Accept", "application/vnd.github+json")
            .build()
}</pre>



<p>Quite a few things are happening here, so let&#8217;s dive into each one. </p>



<p>Firstly, we annotate the class with <code>@Configuration</code> and <code>@EnableConfigurationproperties</code>. The second annotation is necessary to for the previous steps to work. </p>



<p>Then, we inject the <code>GitHubApiProperties</code> instance and use its values to configure a new WebClient bean. This configuration is quite straightforward. We set the base URL and a bunch of headers that will be sent with <strong>every request</strong>: the authorization token, GH API version, and the accept header (those two are specific to the GitHub API, so let&#8217;s focus on that too much).  </p>



<h3 class="wp-block-heading" id="h-prepare-model-classes">Prepare Model Classes</h3>



<p>With that done, let&#8217;s prepare a bunch of data classes that we will need to deserialize JSON responses from the API (+ one exception class). If you would like to add other fields, please check out the documentation link I shared with you before. </p>



<p>As the first step, let&#8217;s add the <code>model</code> package and the <code>PageableGitHubResponse</code>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class PageableGitHubResponse&lt;T>(
    val items: List&lt;T>,
    val hasMoreItems: Boolean,
)</pre>



<p>The API endpoints allow us to get only a chunk of data using the <code>page</code> and <code>per_page</code> parameters. And this class can be reused whenever we&#8217;re using a paginated endpoint. </p>



<p>As the next step, let&#8217;s implement the <code>GitHubRepoResponse</code> along with <code>GitHubOwnerResponse</code>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">data class GitHubRepoResponse(
    val fork: Boolean,
    val name: String,
    val owner: GitHubOwnerResponse,
)

data class GitHubOwnerResponse(
    val login: String,
)</pre>



<p>As I mentioned at the beginning of this paragraph, we need those two in order to deserialize the actual JSON response payload. </p>



<p>Lastly, let&#8217;s add the <code>UpstreamApiException</code>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.springframework.http.HttpStatusCode

data class UpstreamApiException(
    val msg: String,
    val statusCode: HttpStatusCode,
) : RuntimeException(msg)</pre>



<p>This way, we will be able to throw custom exceptions. Such an exception could be handled later, for example with <a href="https://blog.codersee.com/exception-handling-with-restcontrolleradvice-and-exceptionhandler/" target="_blank" rel="noreferrer noopener">@RestControllerAdvice</a>.</p>



<h3 class="wp-block-heading" id="h-make-use-of-webclient">Make Use Of WebClient</h3>



<p>Finally, let&#8217;s combine all of that together. </p>



<p>So, let&#8217;s add the <code>api</code> package and implement the <code>GitHubApi</code> class:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Component
class GitHubApi(
  private val webClient: WebClient,
) {

  suspend fun listRepositoriesByUsername(
    username: String,
    page: Int,
    perPage: Int,
  ): PageableGitHubResponse&lt;GitHubRepoResponse>? =
    webClient.get()
      .uri("/users/$username/repos?page=$page&amp;per_page=$perPage")
      .awaitExchangeOrNull(::mapToPageableResponse)
}</pre>



<p>Don&#8217;t worry about the <code>mapToPageableResponse</code>, we will add it in a moment. </p>



<p>But before that, let&#8217;s analyze the above code. </p>



<p>Firstly, we annotate the class as the <code>@Component</code> to make it a Spring bean and inject the <code>WebClient</code> instance we configured earlier. We don&#8217;t have other WebClient instances, so there is no need to use <code>@Qualifier</code> or anything like that. </p>



<p>Following, we add the <code>listRepositoriesByUsername</code> function that lets us pass the <code>username</code> along with <code>page</code> and <code>perPage</code>. This way, we make this function reusable and allow the invoker to decide how to tackle the pagination. </p>



<p>Additionally, we mark it as a suspend function because the <code>awaitExchangeOrNull</code> is a suspend function. However, if you are interested in this topic, then I refer you to my other article about <a href="https://blog.codersee.com/spring-webclient-with-kotlin-coroutines/" target="_blank" rel="noreferrer noopener">WebClient with coroutines</a>. </p>



<p>Lastly, let&#8217;s add the missing code:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private suspend inline fun &lt;reified T> mapToPageableResponse(clientResponse: ClientResponse): PageableGitHubResponse&lt;T>? {
  val hasNext = checkIfMorePagesToFetch(clientResponse)

  return when (val statusCode = clientResponse.statusCode()) {
    HttpStatus.OK ->
      PageableGitHubResponse(
        items = clientResponse.awaitBody&lt;List&lt;T>>(),
        hasMoreItems = hasNext,
      )

    HttpStatus.NOT_FOUND -> null

    else -> throw UpstreamApiException(
      msg = "GitHub API request failed.",
      statusCode = statusCode,
    )
  }
}

fun checkIfMorePagesToFetch(clientResponse: ClientResponse) =
  clientResponse.headers()
    .header("link")
    .firstOrNull()
    ?.contains("next")
    ?: false</pre>



<p>Long story short, the above code works as follows: </p>



<ol class="wp-block-list">
<li>Firstly, we take the response and check if there are more pages. How? Well, without going into details, GitHub API returns the <code>link</code> header. And if its value contains the <code>rel="next"</code>, it means that there are more pages to fetch. </li>



<li>Finally, we check the status code. If it is <code>200 OK</code>, we simply read the JSON value. When we get <code>404 Not Found</code>, we return null (we can expect this status code when we pass a non-existing username, and in my opinion, this case is not exceptional). And whenever we receive another status code, we simply throw the <code>UpstreamApiException</code>.</li>
</ol>



<h2 class="wp-block-heading" id="h-webclient-integration-testing-with-wiremock">WebClient Integration Testing With WireMock</h2>



<p>Excellent, at this point we have (almost) everything we need to test our WebClient implementation with WireMock. </p>



<p>We will see only a few example test cases that you will be able to easily adapt according to your needs:</p>



<ul class="wp-block-list">
<li>200 OK response with an empty list, 200 OK with items, and more pages, and 200 OK with items and no more pages to fetch</li>



<li>404 Not Found, </li>



<li>401 Unauthorized</li>
</ul>



<p>When you will be implementing your own integration tests, this is the moment when you should do the homework and analyze the API you are working with. What are the possible happy paths? How should your code behave in case of any error status code? What if we add some latency? And many, many more 🙂 </p>



<h3 class="wp-block-heading" id="h-additional-dependencies">Additional Dependencies</h3>



<p>At this point, we defined our test cases, so we are ready to get our hands dirty. </p>



<p>So, let&#8217;s start by adding the necessary dependencies: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">testImplementation("org.springframework.cloud:spring-cloud-contract-wiremock:4.1.1")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.8.0")</pre>



<p>As we can see, the first one- the Spring Cloud Contract WireMock module- allows us to use WireMock in our app, whereas the <code>kotlinx-coroutines-test</code> is necessary due to our coroutines WebClient implementation.</p>



<h3 class="wp-block-heading" id="h-add-expected-json-files">Add Expected JSON Files</h3>



<p>So, if we know what test cases we would like to test, we should prepare the example JSON API responses. </p>



<p>Personally, whenever working with WireMock I am a big fan of externalizing the expected JSON files. We put them inside the <code>/test/resources</code> directory and refer to them later in the tests. This way, we can improve the readability of the test classes. Of course, <strong>unless we want to prepare JSON responses dynamically</strong>. </p>



<p>In our case, we could simply invoke the GitHub API and persist responses for different cases. This way, we prepare the following files and put them inside the <code>/test/resources/responses/external/github</code>: </p>



<ul class="wp-block-list">
<li></li>
</ul>



<ul class="wp-block-list">
<li>list_github_repositories_200_OK_empty_list.json</li>



<li>list_github_repositories_200_OK_page_1.json</li>



<li>list_github_repositories_401_UNAUTHORIZED.json</li>



<li>list_github_repositories_404_NOT_FOUND.json</li>
</ul>



<p>You can find all of these files in my GH repo <a href="https://github.com/codersee-blog/integration-testing-spring-webflux-webclient-wiremock/tree/main/src/test/resources/responses/external/github" target="_blank" rel="noreferrer noopener">here</a>. </p>



<p>The example for <code>401 Unauthorized</code> looks as follows:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="json" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">{
  "message": "Bad credentials",
  "documentation_url": "https://docs.github.com/rest"
}</pre>



<h3 class="wp-block-heading" id="h-prepare-util-function">Prepare Util Function</h3>



<p>As the last thing before we implement our test class, let&#8217;s add the util function inside the <code>util</code> package (of course, in tests). </p>



<p>This function will be responsible for reading JSON files inside the test resources as String values:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import org.springframework.core.io.ClassPathResource

fun getResponseBodyAsString(path: String): String =
    ClassPathResource(path).getContentAsString(
        Charsets.UTF_8,
    )</pre>



<h3 class="wp-block-heading" id="h-implement-githubapitest-class">Implement GitHubApiTest Class</h3>



<p>Finally, let&#8217;s start implementing the <code>GitHubApiTest</code> class: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">private const val TEST_KEY = "TEST_KEY"
private const val TEST_PORT = 8082
private const val TEST_VERSION = "2022-11-28"

@AutoConfigureWireMock(port = TEST_PORT)
@TestPropertySource(
  properties = [
    "api.github.url=http://localhost:${TEST_PORT}",
    "api.github.key=$TEST_KEY",
    "api.github.version=$TEST_VERSION",
  ],
)
@SpringBootTest(
  webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT,
)
class GitHubApiTest {
  @Autowired
  private lateinit var wireMockServer: WireMockServer

  @Autowired
  private lateinit var gitHubApi: GitHubApi

  private val page = 1
  private val perPage = 2
  private val username = UUID.randomUUID().toString()

}</pre>



<p>Conceptually, everything starts with the <code>@SpringBootTest</code> and <code>@AutoConfigureWireMock</code> annotations.</p>



<p>We use the <code>@SpringBootTest</code> annotation in Spring Boot integration tests. This way a new ApplicationContext will be created. In our case, we set the <code>webEnvironment</code> with <code>RANDOM_PORT</code> value, so that a reactive context listening on the random port is created. </p>



<p>Additionally, we combine that together with <code>@AutoConfigureWireMock</code> and fixed test port. This way a WireMock server will be started as a part of Application Context. </p>



<p>Lastly, we do 3 things: </p>



<ol class="wp-block-list">
<li>We use the <code>@TestPropertySource</code> to pass values for properties.</li>



<li>We inject the <code>WireMockServer</code> and <code>GitHubApi</code> instances that we will work with later. Please note that we can do that just like we would do with a standard, non-test, Spring component. </li>



<li>We prepare some dummy data for <code>page</code>, <code>perPage</code>, and <code>username</code> values we will need for testing. </li>
</ol>



<p>As a note of comment from my side- this &#8220;skeleton&#8221; is useful whenever working with WebClient and WireMock.</p>



<h3 class="wp-block-heading" id="h-test-404-not-found-api-response-case">Test 404 Not Found API Response Case</h3>



<p>Wonderful! </p>



<p>As the first test, let&#8217;s start with the <code>404 Not Found</code> case. Usually, we will start with happy path cases, but for learning purposes, this one is the shortest case 😉 </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given 404 NOT FOUND response When fetching repository by username Then should return null`() = runTest {
  // Given
  wireMockServer.stubFor(
    WireMock.get(WireMock.urlEqualTo("/users/$username/repos?page=$page&amp;per_page=$perPage"))
      .withHeader("Authorization", WireMock.equalTo("Bearer $TEST_KEY"))
      .withHeader("X-GitHub-Api-Version", WireMock.equalTo(TEST_VERSION))
      .withHeader("Accept", WireMock.equalTo("application/vnd.github+json"))
      .willReturn(
        WireMock.aResponse()
          .withStatus(HttpStatus.NOT_FOUND.value())
          .withHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
          .withBody(
            getResponseBodyAsString("/responses/external/github/list_github_repositories_404_NOT_FOUND.json"),
          ),
      ),
  )

  // When
  val result = gitHubApi.listRepositoriesByUsername(username, page, perPage)

  // Then
  Assertions.assertNull(result)
}</pre>



<p>We mark our test with the <code>@Test</code> (JUnit 5), specify the meaningful name for the test (with awesome Kotlin backticks), and wrap our test with <code>runTest</code>. The last one is necessary as we are working with coroutines and invoke the suspended function. Long story short, in JVM it will behave just like <code>runBlocking</code> (but it will skip delays). </p>



<p>Next comes the WireMock part. And to be even more specific- <strong>stubbing.</strong> </p>



<p>Stubbing is nothing else than &#8220;the ability to return canned HTTP responses for requests matching criteria&#8221; (from docs). Simply said, whenever an outgoing request that matches our criteria is made, a mocked response configured in <code>willReturn</code> is returned. </p>



<p>So, as we can see, the above logic will work only when: </p>



<ul class="wp-block-list">
<li>the GET request is made, </li>



<li>URL matches, </li>



<li>Headers sent have appropriate values </li>
</ul>



<p>And this part <strong>already tests our logic.</strong> Pretty neat, isn&#8217;t it? 🙂 </p>



<p>Lastly, we simply invoke the function and assert that <code>null</code> is returned. Which confirms that everything is working fine. </p>



<h3 class="wp-block-heading" id="h-test-401-unauthorized">Test 401 Unauthorized </h3>



<p>As we already started with error cases, let&#8217;s verify that whenever the endpoint returns <code>401 Unauthorized</code>, the <code>UpstreamApiException</code> is thrown:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given 401 UAUTHORIZED response When fetching repository by username Then should throw UpstreamApiException`() = runTest {
  // Given
  wireMockServer.stubFor(
    WireMock.get(WireMock.urlEqualTo("/users/$username/repos?page=$page&amp;per_page=$perPage"))
      .withHeader("Authorization", WireMock.equalTo("Bearer $TEST_KEY"))
      .withHeader("X-GitHub-Api-Version", WireMock.equalTo(TEST_VERSION))
      .withHeader("Accept", WireMock.equalTo("application/vnd.github+json"))
      .willReturn(
        WireMock.aResponse()
          .withStatus(HttpStatus.UNAUTHORIZED.value())
          .withHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
          .withBody(
            getResponseBodyAsString("/responses/external/github/list_github_repositories_401_UNAUTHORIZED.json"),
          ),
      ),
  )

  // When
  val exception = assertThrows&lt;UpstreamApiException> {
    gitHubApi.listRepositoriesByUsername(username, page, perPage)
  }

  // Then
  assertNotNull(exception)

  assertEquals("GitHub API request failed.", exception.msg)
  assertEquals(HttpStatus.UNAUTHORIZED, exception.statusCode)
}</pre>



<p>As we can see, the logic responsible for stubbing only slightly changed. </p>



<p>The interesting part here is the <code>assertThrows</code>, which not only makes sure that the exception of an appropriate type is thrown but also returns it. This way we can make additional assertions.</p>



<h3 class="wp-block-heading" id="h-verify-200-ok-with-empty-list">Verify 200 OK With Empty List</h3>



<p>Following, let&#8217;s cover the empty list case:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given 200 OK response with empty list When fetching repository by username Then should return repository with correct properties and has next false`() =
  runTest {
    // Given
    val linkHeader = """&lt;https://api.github.com/user/64011387/repos?page=3&amp;per_page=2>; rel="prev","""

    wireMockServer.stubFor(
      WireMock.get(WireMock.urlEqualTo("/users/$username/repos?page=$page&amp;per_page=$perPage"))
        .withHeader("Authorization", WireMock.equalTo("Bearer $TEST_KEY"))
        .withHeader("X-GitHub-Api-Version", WireMock.equalTo(TEST_VERSION))
        .withHeader("Accept", WireMock.equalTo("application/vnd.github+json"))
        .willReturn(
          WireMock.aResponse()
            .withStatus(HttpStatus.OK.value())
            .withHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
            .withHeader(HttpHeaders.LINK, linkHeader)
            .withBody(
              getResponseBodyAsString("/responses/external/github/list_github_repositories_200_OK_empty_list.json"),
            ),
        ),
    )

    // When
    val result = gitHubApi.listRepositoriesByUsername(username, page, perPage)

    // Then
    val expected =
      PageableGitHubResponse(
        items = emptyList&lt;GitHubRepoResponse>(),
        hasMoreItems = false,
      )

    assertEquals(expected, result)
  }</pre>



<p>This time, we assign the returned value to the <code>result</code> and compare that with the <code>expected</code>. </p>



<h3 class="wp-block-heading" id="h-check-200-ok-with-has-next-true">Check 200 OK With Has Next True</h3>



<p>Last before least, let&#8217;s make sure that we got the expected objects in a list and that the logic responsible for the <code>link</code> header check returns true:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given 200 OK response with payload When fetching repository by username Then should return repository with correct properties and has next true`() =
  runTest {
    // Given
    val linkHeader = """&lt;https://api.github.com/user/64011387/repos?page=3&amp;per_page=2>; rel="next","""

    wireMockServer.stubFor(
      WireMock.get(WireMock.urlEqualTo("/users/$username/repos?page=$page&amp;per_page=$perPage"))
        .withHeader("Authorization", WireMock.equalTo("Bearer $TEST_KEY"))
        .withHeader("X-GitHub-Api-Version", WireMock.equalTo(TEST_VERSION))
        .withHeader("Accept", WireMock.equalTo("application/vnd.github+json"))
        .willReturn(
          WireMock.aResponse()
            .withStatus(HttpStatus.OK.value())
            .withHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
            .withHeader(HttpHeaders.LINK, linkHeader)
            .withBody(
              getResponseBodyAsString("/responses/external/github/list_github_repositories_200_OK_page_1.json"),
            ),
        ),
    )

    // When
    val result = gitHubApi.listRepositoriesByUsername(username, page, perPage)

    // Then
    val expected =
      PageableGitHubResponse(
        items =
        listOf(
          GitHubRepoResponse(
            fork = false,
            name = "controlleradvice-vs-restcontrolleradvice",
            owner = GitHubOwnerResponse(login = "codersee-blog"),
          ),
          GitHubRepoResponse(
            fork = false,
            name = "freecodecamp-spring-boot-kotlin-excel",
            owner = GitHubOwnerResponse(login = "codersee-blog"),
          ),
        ),
        hasMoreItems = true,
      )

    assertEquals(expected, result)
  }</pre>



<h3 class="wp-block-heading" id="h-test-200-ok-with-has-next-false">Test 200 OK With Has Next False</h3>



<p>And finally, let&#8217;s double-check the flag logic:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `Given 200 OK response with payload When fetching repository by username Then should return repository with correct properties and has next false`() =
  runTest {
    // Given
    val linkHeader = """&lt;https://api.github.com/user/64011387/repos?page=3&amp;per_page=2>; rel="prev","""

    wireMockServer.stubFor(
      WireMock.get(WireMock.urlEqualTo("/users/$username/repos?page=$page&amp;per_page=$perPage"))
        .withHeader("Authorization", WireMock.equalTo("Bearer $TEST_KEY"))
        .withHeader("X-GitHub-Api-Version", WireMock.equalTo(TEST_VERSION))
        .withHeader("Accept", WireMock.equalTo("application/vnd.github+json"))
        .willReturn(
          WireMock.aResponse()
            .withStatus(HttpStatus.OK.value())
            .withHeader(HttpHeaders.CONTENT_TYPE, "application/json; charset=utf-8")
            .withHeader(HttpHeaders.LINK, linkHeader)
            .withBody(
              getResponseBodyAsString("/responses/external/github/list_github_repositories_200_OK_page_1.json"),
            ),
        ),
    )

    // When
    val result = gitHubApi.listRepositoriesByUsername(username, page, perPage)

    // Then
    val expected =
      PageableGitHubResponse(
        items =
        listOf(
          GitHubRepoResponse(
            fork = false,
            name = "controlleradvice-vs-restcontrolleradvice",
            owner = GitHubOwnerResponse(login = "codersee-blog"),
          ),
          GitHubRepoResponse(
            fork = false,
            name = "freecodecamp-spring-boot-kotlin-excel",
            owner = GitHubOwnerResponse(login = "codersee-blog"),
          ),
        ),
        hasMoreItems = false,
      )

    assertEquals(expected, result)
  }</pre>



<h3 class="wp-block-heading" id="h-integration-tests-with-wiremock-and-webclient-summary">Integration Tests With WireMock And WebClient Summary</h3>



<p>And basically, that&#8217;s all for this tutorial on how to perform integration testing for Spring WebClient that invokes external REST APIs with WireMock and JUnit 5.</p>



<p>I hope you enjoyed this one and I recommend you check out my other articles related to <a href="https://blog.codersee.com/category/spring/">Spring Framework</a>.</p>
<p>The post <a href="https://blog.codersee.com/integration-tests-webclient-wiremock/">Integration Tests for WebClient with WireMock</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/integration-tests-webclient-wiremock/feed/</wfw:commentRss>
			<slash:comments>1</slash:comments>
		
		
			</item>
		<item>
		<title>Testing Micronaut Application in Kotlin</title>
		<link>https://blog.codersee.com/testing-micronaut-appplication-kotlin/</link>
					<comments>https://blog.codersee.com/testing-micronaut-appplication-kotlin/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Wed, 10 Jan 2024 08:24:44 +0000</pubDate>
				<category><![CDATA[Micronaut]]></category>
		<category><![CDATA[docker]]></category>
		<category><![CDATA[JUnit 5]]></category>
		<category><![CDATA[MockK]]></category>
		<category><![CDATA[REST Assured]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9508620</guid>

					<description><![CDATA[<p>In this, practical tutorial, I will show you how to test a REST API created with Micronaut, Kotlin and MongoDB.</p>
<p>The post <a href="https://blog.codersee.com/testing-micronaut-appplication-kotlin/">Testing Micronaut Application in Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>Hello and welcome to my next article, in which I will show you <strong>how to test a Micronaut application in Kotlin</strong>. </p>



<p>To be even more specific- we will work with an application that exposes a <strong>REST API</strong> and connects to <strong>MongoDB</strong>. If you would like to learn how to do that step-by-step, then you can check out <a href="https://blog.codersee.com/micronaut-with-mongodb-and-kotlin-revisited-2022/" target="_blank" rel="noreferrer noopener">my other article</a>. (But don&#8217;t worry, we will see its code snippets in this tutorial, too). </p>



<p>For testing, we&#8217;re going to use <strong>JUnit 5</strong>, <strong>MockK</strong>, <strong>REST Assured</strong>, as well as the <strong>@MicronautTest</strong> and <strong>Micronaut Test Resources</strong>.</p>



<h2 class="wp-block-heading" id="h-video-tutorial">Video Tutorial</h2>



<p>If you prefer <strong>video content</strong>, then check out my video:</p>



<div style="text-align: center; width: 90%; margin-left: 5%;">
<a href="https://blog.codersee.com/testing-micronaut-appplication-kotlin/"><img decoding="async" src="https://blog.codersee.com/wp-content/plugins/wp-youtube-lyte/lyteCache.php?origThumbUrl=%2F%2Fi.ytimg.com%2Fvi%2FH-LbDsi4qKg%2Fhqdefault.jpg" alt="YouTube Video"></a><br /><br /></p></div>



<p>If you find this content useful,<strong> please leave a subscription&nbsp;</strong> 😉</p>



<h2 class="wp-block-heading" id="h-micronaut-project-overview">Micronaut Project Overview</h2>



<p>Let&#8217;s start everything by <strong>checking the project we will test today</strong>. Of course, we will focus on the most important parts, and for the full source code, I invite you to <a href="https://github.com/codersee-blog/kotlin-micronaut-testing" target="_blank" rel="noreferrer noopener">this GitHub repository</a>.</p>



<h3 class="wp-block-heading" id="h-application-properties">Application Properties</h3>



<p>In our project, we introduce 3 application properties files: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// application.properties
micronaut.application.name=micronaut-testing

// application-mongo.properties
mongodb.uri=mongodb://localhost:27017/example

// application-test.properties
mongodb.package-names=com.codersee.model</pre>



<p>The application name is the default property inserted when generating a new project. </p>



<p>Nevertheless, the two remaining are created on purpose. With their names- <code>*mongo</code>, <code>*test</code>&#8211; we instruct Micronaut that it should consider them only when <code>mongo</code> and <code>test</code> profiles are active. </p>



<p>But why this way? Well, to avoid two issues. </p>



<h3 class="wp-block-heading" id="h-mongodb-connection-issues-with-micronaut-test-resources">MongoDB Connection Issues with Micronaut Test Resources</h3>



<p>So, let&#8217;s start everything by explaining <strong>why we don&#8217;t put the Mongo URI inside the main properties</strong>.</p>



<p>Well, when we use the Micronaut Test Resources, MongoDB support will start a MongoDB container and provide the value of the <code>mongodb.uri</code> property. </p>



<p>Nevertheless, <strong>this won&#8217;t happen</strong> when we explicitly set the URI in the application properties. And that&#8217;s why we want to make this setting available <strong>only when we set the environment to <code>mongo</code>.</strong></p>



<h3 class="wp-block-heading" id="h-codeccachekey-issue">CodecCacheKey Issue</h3>



<p>Additionally, if we don&#8217;t specify explicitly the package name, where our model classes live, we&#8217;re going to end up with the following issue when running our Micronaut tests: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[io-executor-thread-1] ERROR i.m.http.server.RouteExecutor - Unexpected error occurred: Can't find a codec for CodecCacheKey{clazz=class com.codersee.model.AppUser, types=null}.
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for CodecCacheKey{clazz=class com.codersee.model.AppUser, types=null}.
  at org.bson.internal.ProvidersCodecRegistry.lambda$get$0(ProvidersCodecRegistry.java:87)
  at java.base/java.util.Optional.orElseGet(Optional.java:364)
  at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:80)
  at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:50)
  at com.mongodb.internal.operation.Operations.createFindOperation(Operations.java:188)
...</pre>



<p>To me, looks like a bug. But thankfully, we can easily avoid that by putting that in the <code>application-test.properties</code> (which is used in tests by default).</p>



<h3 class="wp-block-heading" id="h-models">Models</h3>



<p>Following, we introduce a bunch of models:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// Address.kt: 

import io.micronaut.serde.annotation.Serdeable

@Serdeable.Serializable
@Serdeable.Deserializable
data class Address(
  val street: String,
  val city: String,
  val code: Int
)

// AppUser.kt:

import io.micronaut.data.annotation.GeneratedValue
import io.micronaut.data.annotation.Id
import io.micronaut.data.annotation.MappedEntity

@MappedEntity
data class AppUser(
  @field:Id
  @field:GeneratedValue
  val id: String? = null,
  val firstName: String,
  val lastName: String,
  val email: String,
  val address: Address
)

// AppUserRequest.kt: 

import io.micronaut.serde.annotation.Serdeable

@Serdeable.Deserializable
data class AppUserRequest(
  val firstName: String,
  val lastName: String,
  val email: String,
  val street: String,
  val city: String,
  val code: Int
)

// SearchRequest.kt:

import io.micronaut.serde.annotation.Serdeable

@Serdeable.Deserializable
data class SearchRequest(val name: String)</pre>



<p>Those classes are either used to persist/retrieve data from MongoDB or when deserializing JSON payloads into the objects. </p>



<h3 class="wp-block-heading" id="h-repository">Repository</h3>



<p>Following, we have a repository layer responsible for communicating with our storage:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// AppUserRepository.kt: 

import com.codersee.model.AppUser
import io.micronaut.data.mongodb.annotation.MongoFindQuery
import io.micronaut.data.mongodb.annotation.MongoRepository
import io.micronaut.data.repository.CrudRepository

@MongoRepository
interface AppUserRepository : CrudRepository&lt;AppUser, String> {

  fun findByFirstNameEquals(firstName: String): List&lt;AppUser>

  @MongoFindQuery("{ firstName: { \$regex: :name}}")
  fun findByFirstNameLike(name: String): List&lt;AppUser>
}</pre>



<h3 class="wp-block-heading" id="h-service">Service</h3>



<p>Nextly, the service layer, where we inject the repository and encapsulate its methods: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// AppUserService.kt:

import com.codersee.model.Address
import com.codersee.model.AppUser
import com.codersee.model.AppUserRequest
import com.codersee.repository.AppUserRepository
import io.micronaut.http.HttpStatus
import io.micronaut.http.exceptions.HttpStatusException
import jakarta.inject.Singleton

@Singleton
class AppUserService(
  private val appUserRepository: AppUserRepository
) {

  fun create(userRequest: AppUserRequest): AppUser =
    appUserRepository.save(
      userRequest.toAppUserEntity()
    )

  fun findAll(): List&lt;AppUser> =
    appUserRepository
      .findAll()
      .toList()

  fun findById(id: String): AppUser =
    appUserRepository.findById(id)
      .orElseThrow { HttpStatusException(HttpStatus.NOT_FOUND, "User with id: $id was not found.") }

  fun update(id: String, updateRequest: AppUserRequest): AppUser {
    val foundUser = findById(id)

    val updatedEntity =
      updateRequest
        .toAppUserEntity()
        .copy(id = foundUser.id)

    return appUserRepository.update(updatedEntity)
  }

  fun deleteById(id: String) {
    val foundUser = findById(id)

    appUserRepository.delete(foundUser)
  }

  fun findByNameLike(name: String): List&lt;AppUser> =
    appUserRepository
      .findByFirstNameLike(name)

  private fun AppUserRequest.toAppUserEntity(): AppUser {
    val address = Address(
      street = this.street,
      city = this.city,
      code = this.code
    )

    return AppUser(
      id = null,
      firstName = this.firstName,
      lastName = this.lastName,
      email = this.email,
      address = address
    )
  }
}</pre>



<h3 class="wp-block-heading" id="h-controller">Controller </h3>



<p>And lastly, the place where we expose our REST endpoints: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">// AppUserController.kt: 

import com.codersee.model.AppUserRequest
import com.codersee.service.AppUserService
import com.codersee.model.SearchRequest
import com.codersee.model.AppUser
import io.micronaut.http.HttpStatus
import io.micronaut.http.annotation.*
import io.micronaut.scheduling.TaskExecutors
import io.micronaut.scheduling.annotation.ExecuteOn

@Controller("/users")
@ExecuteOn(TaskExecutors.IO)
class AppUserController(
  private val appUserService: AppUserService
) {

  @Get
  fun findAllUsers(): List&lt;AppUser> =
    appUserService.findAll()

  @Get("/{id}")
  fun findById(@PathVariable id: String): AppUser =
    appUserService.findById(id)

  @Post
  @Status(HttpStatus.CREATED)
  fun createUser(@Body request: AppUserRequest): AppUser =
    appUserService.create(request)

  @Post("/search")
  fun searchUsers(@Body searchRequest: SearchRequest): List&lt;AppUser> =
    appUserService.findByNameLike(
      name = searchRequest.name
    )

  @Put("/{id}")
  fun updateById(
    @PathVariable id: String,
    @Body request: AppUserRequest
  ): AppUser =
    appUserService.update(id, request)

  @Delete("/{id}")
  @Status(HttpStatus.NO_CONTENT)
  fun deleteById(@PathVariable id: String) =
    appUserService.deleteById(id)
}</pre>



<h2 class="wp-block-heading" id="h-simple-kotlin-testing-in-micronaut">Simple Kotlin Testing in Micronaut</h2>



<p>Excellent. At this point, we know what exactly we are going to test. </p>



<p>And as the first approach we&#8217;re going to see will be a plain, old unit test. </p>



<p>Why? </p>



<p>Because at the end of the day, <strong>that&#8217;s what we will be dealing with most of the time</strong>. </p>



<p>So with that said, let&#8217;s take a look at the example test: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">  import com.codersee.repository.AppUserRepository
import io.mockk.every
import io.mockk.mockk
import io.mockk.verify
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

class AppUserServiceTest {

  private val appUserRepository = mockk&lt;AppUserRepository>()

  private val appUserService = AppUserService(appUserRepository)

  @Test
  fun `should return empty user list`() {
    every {
      appUserRepository.findAll()
    } returns emptyList()

    val result = appUserService.findAll()

    assertTrue(result.isEmpty())

    verify(exactly = 1) { appUserRepository.findAll() }
  }
}</pre>



<p>As we can see above, we simply mock (with MockK) the <em>AppUserRepository </em>and inject it into the <em>AppUserService </em>instance.</p>



<p>Then, we specify that all invocations of the <code>findAll</code> method must return the empty list (with <code>every</code>). </p>



<p>Lastly, we assert that the <code>findAll</code> method from our service returns an empty list (<code>assertTrue</code>) and that the <code>findAll</code> method from the repository was invoked only once (<code>verify</code>). </p>



<p>Nevertheless, we&#8217;re not going to spend too much here right now as this tutorial focuses on Micronaut testing in Kotlin. If you are interested in learning more about these tools, then let me know in the comments section 🙂 </p>



<h2 class="wp-block-heading" id="h-integration-testing-with-micronauttest">Integration Testing with @MicronautTest</h2>



<p>With all of that done, let&#8217;s see how the Micronaut framework helps us with testing and a few interesting cases that will help us in real life. </p>



<h3 class="wp-block-heading" id="h-what-is-a-micronauttest">What is a @MicronautTest? </h3>



<p>Let&#8217;s start everything by explaining what exactly is the <strong>@MicronautTest</strong>.</p>



<p>In simple words, it&#8217;s an annotation that we can put on the test class to mark it a Micronaut test (no sh&#8230; Sherlock 🙂 :</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import io.micronaut.test.extensions.junit5.annotation.MicronautTest

@MicronautTest
class SomeTest {
  // tests
}</pre>



<p>In practice, it means that <strong>when we run a test with that annotation, it will run a real application</strong>. It will use internal Micronaut features with no mocking. So at this point, we can clearly see that this will be the right solution for <strong>integration testing.</strong></p>



<p>Moreover, this annotation can be used not only with <strong>JUnit 5</strong>, but also with <strong>Spock</strong>, <strong>Kotest</strong>, and <strong>Kotest 5</strong>. </p>



<h3 class="wp-block-heading" id="h-micronauttest-configuration-options">@MicronautTest Configuration Options </h3>



<p>The @MicronautTest allows us to configure a few properties, like the environments we want to run our test with, the packages to scan, or whether the automatic transaction wrapping should be enabled, or not:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import io.micronaut.test.extensions.junit5.annotation.MicronautTest

@MicronautTest(
  environments = ["env-1, env-2"],
  packages = ["com.codersee.somepackage"],
  transactional = false
)
class SomeTest {
  // tests
}</pre>



<p>For the full list of options, I highly encourage you to check out the docs (we can do that for instance in IntelliJ IDEA by clicking on the annotation with the left mouse button when we keep the left ctrl pressed). </p>



<h3 class="wp-block-heading" id="h-what-are-micronaut-test-resources">What Are Micronaut Test Resources? </h3>



<p>At the beginning of this tutorial, I mentioned the Micronaut Test Resources and I would like to make sure that we are on the same page with them. </p>



<p>So basically, Micronaute Test Resources <strong>integrates seamlessly with Testcontainers to provide throwaway containers for testing</strong>. But, we need to remember that Testcontainers <strong>require Docker-API compatible container runtime</strong> (in simple words- either Docker installed locally, or the Testcontainers Cloud). </p>



<p>In our case, we would like to do integration tests that require MongoDB. We could make use of the real database (which sometimes may be the case for you), provide some H2 database (not the best approach), or integrate Testcontainers. Thankfully, we don&#8217;t need to do that and the only thing we need is the appropriate import in our project: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">plugins {
    id("io.micronaut.test-resources") version "4.2.1"
}</pre>



<p>As a reminder, I want to emphasize that <strong>test resources will be used only when the <code>datasources.default.url</code> is missing.</strong> (and that&#8217;s why we removed the URI for MongoDB from tests). <strong> </strong> </p>



<h2 class="wp-block-heading" id="h-integration-tests-with-rest-assured">Integration Tests With REST Assured</h2>



<p>With all of that said, let&#8217;s combine everything together and test our Kotlin Micronaut application with JUnit 5 and REST Assured. </p>



<p>To do so, we must remember to add the necessary import: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">testImplementation("io.micronaut.test:micronaut-test-rest-assured")</pre>



<h3 class="wp-block-heading" id="h-verify-status-codes-and-headers">Verify Status Codes and Headers</h3>



<p>Let&#8217;s start with a simple request to the <code>GET /users</code> endpoint: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@MicronautTest
class AppUserControllerTestWithoutMocking {

  @Test
  fun `should return 200 OK on GET users`(spec: RequestSpecification) {
    spec
      .`when`()
      .get("/users")
      .then()
      .statusCode(200)
      .header("Content-Type", "application/json")
  }

}</pre>



<p>As I mentioned previously- by default, with @MicronautTest the real application is started. Moreover, nothing here is mocked, so the Mongo test container delivered by the Micronaut Test Resources is used.</p>



<p>Thanks to the dedicated module we added, we can inject the <code>RequestSpecification</code> into our tests and easily validate our endpoint. </p>



<p>In this case, we <strong>perform a GET request</strong> and verify that the <strong>response status code is 200 OK</strong> and the response <strong><code>Content-Type</code> header value is <code>application/json</code></strong>. </p>



<h3 class="wp-block-heading" id="h-verify-404-not-found">Verify 404 Not Found</h3>



<p>Similarly, we can verify that no entry is present in the database: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should return 404 Not Found on GET user by ID`(spec: RequestSpecification) {
  spec
    .`when`()
    .get("/users/123123123123123123121231")
    .then()
    .statusCode(404)
}</pre>



<p>This test will be also good proof that entries inserted to MongoDB in other tests do not affect other tests. </p>



<h3 class="wp-block-heading" id="h-extract-and-json-array-in-rest-assured">Extract and JSON Array in REST Assured</h3>



<p>Nextly, let&#8217;s take a look at the more complicated example:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@Test
fun `should create a user`(spec: RequestSpecification) {
  val request = AppUserRequest(
    firstName = "Piotr",
    lastName = "Wolak",
    email = "contact@codersee.com",
    street = "Street",
    city = "City",
    code = 123,
  )

  spec
    .`when`()
    .contentType(ContentType.JSON)
    .body(request)
    .post("/users")
    .then()
    .statusCode(201)

  val list = spec
    .`when`()
    .get("/users")
    .then()
    .statusCode(200)
    .body("size()", `is`(1))
    .extract()
    .`as`(object : TypeRef&lt;List&lt;AppUser>>() {})

  assertEquals(1, list.size)

  val createdUser = list.first()

  assertEquals(request.firstName, createdUser.firstName)
  assertEquals(request.street, createdUser.address.street)
}</pre>



<p>This time, we do a bunch of more interesting things. </p>



<p>Firstly, we make the <strong>POST request </strong>with a request body and <strong>verify that 201 Creates is returned</strong>. </p>



<p>After that, we call the <code>GET /users</code> endpoint to get a list of users. When we get the response, we <strong>verify that the JSON array size is equal to 1</strong> (with the <code>.body("size()", is(1))</code> call). Lastly, we <strong>make use of the extract().`as</strong>` to convert the payload into the List of AppUser instances. Thanks to that we can easily perform assertions with JUnit 5 functions. </p>



<h3 class="wp-block-heading" id="h-add-kotlin-utils-for-rest-assured">Add Kotlin Utils For REST Assured</h3>



<p>As you probably know, <code>when</code> and <code>as</code> are keywords in Kotlin and that&#8217;s why <strong>we had to use backticks (&#8220;)</strong>.</p>



<p>And to make our lives easier, let&#8217;s add the <code>util</code> package in <code>test</code> and create the <code>TestUtil.kt</code>: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import io.restassured.common.mapper.TypeRef
import io.restassured.response.ValidatableResponse
import io.restassured.specification.RequestSpecification


fun RequestSpecification.whenever(): RequestSpecification {
  return this.`when`()
}

fun &lt;T> ValidatableResponse.extractAs(clazz: Class&lt;T>) =
  this.extract()
    .`as`(clazz)

fun &lt;T> ValidatableResponse.extractAs(typeRef: TypeRef&lt;T>) =
  this.extract()
    .`as`(typeRef)</pre>



<p>As a result, from now on we can simply use the <em>whenever() </em>instead of <em>`when`()</em> and <em>extractAs() </em>instead of <em>extract().`</em>as`(). </p>



<h2 class="wp-block-heading" id="h-reference-the-server-context">Reference The Server / Context </h2>



<p>As the next step, let&#8217;s take a look at how to <strong>reference the server</strong> or <strong>current application context</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@MicronautTest
class InjectingExample{

  @Inject
  private lateinit var context: ApplicationContext

  @Inject
  private lateinit var server: EmbeddedServer

  // tests
}</pre>



<p>Sometimes it can be useful, and as we can see, we can simply inject them using the <strong>@Inject</strong> annotation. </p>



<h2 class="wp-block-heading" id="h-conditionally-run-tests">Conditionally Run Tests</h2>



<p>After that, let&#8217;s see <strong>how we can skip tests execution.</strong> </p>



<p>Why would we need that? </p>



<p>Well, integration tests sometimes can take a lot of time, and the bigger our project becomes, the bigger the chance they become annoying. And because of that, generally, it&#8217;s a good approach to somehow separate them from the faster unit tests. </p>



<p> When testing in Micronaut, we can easily achieve that using the <strong><em>@Requires</em></strong> annotation:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import io.micronaut.context.annotation.Requires
import io.micronaut.test.extensions.junit5.annotation.MicronautTest
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Test

@MicronautTest
@Requires(env = ["integration-test"])
class SomeIntegrationTest {

  @Test
  fun `should perform integration test`() {
    assertTrue(false)
  }

}</pre>



<p>The <strong><em>@MicronautTest</em></strong> annotation <strong>turns tests into beans</strong>. And that&#8217;s why we can use the <strong>@Requires</strong>, just like we would do with a &#8220;standard&#8221; bean.</p>



<p>As a result, tests inside the <code>SomeIntegrationTest</code> will run only, when the <code>integration-test</code> the environment is active. (And we can set that for example by setting the environment variable- <code>MICRONAUT_ENVIRONMENTS=integration-test</code>). </p>



<h2 class="wp-block-heading" id="h-testing-micronaut-with-mockk-mocks">Testing Micronaut With MockK Mocks</h2>



<p>As the last thing in our tutorial about testing Micronaut with Kotlin, let&#8217;s take a look at <strong>how we can mock things using the MockK</strong>.</p>



<p>Could we use Mockito? Yes. However, I find MockK better for Kotlin (DSLs &lt;3 ).</p>



<p>In order to mock a bean in Micronaut, the only thing we need to do is <strong>annotate the method/inner class with the @MockBean annotation</strong>:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@MicronautTest
class AppUserControllerTestWithMocking {

  private val repo: AppUserRepository = mockk&lt;AppUserRepository>()

  @MockBean(AppUserRepository::class)
  fun appUserRepository(): AppUserRepository = repo
}</pre>



<p>As we can see, we introduce the <code>AppUserRepository</code> mock as the <code>repo</code> property, so that later, we will be able to refer to it easily in our test cases. Additionally, we add the function annotated with <code>@MockBean</code>, thus informing Micronaut that the <code>AppUserRepository</code> is the type we want to replace with our mock. </p>



<p>Moreover, thanks to this approach <strong>this mock will be limited only to tests defined in this class</strong>. So we can &#8220;rest assured&#8221; (hue hue) it won&#8217;t interfere with other classes. </p>



<p>As a result, our tests will look, as follows: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@MicronautTest
class AppUserControllerTestWithMocking {

  private val repo: AppUserRepository = mockk&lt;AppUserRepository>()

  @Test
  fun `should return 200 OK on GET users`(spec: RequestSpecification) {
    every {
      repo.findAll()
    } returns emptyList()

    spec
      .whenever()
      .get("/users")
      .then()
      .statusCode(200)
      .header("Content-Type", "application/json")
  }

  @Test
  fun `should return user by ID`(spec: RequestSpecification) {
    val foundUser = AppUser(
      id = "123",
      firstName = "Piotr",
      lastName = "Wolak",
      email = "contact@codersee.com",
      address = Address(
        street = "street",
        city = "city",
        code = 123
      )
    )

    every {
      repo.findById("123")
    } returns Optional.of(foundUser)

    spec
      .whenever()
      .get("/users/123")
      .then()
      .statusCode(200)
      .body("id", equalTo("123"))
      .body("firstName", equalTo("Piotr"))
      .body("address.street", equalTo("street"))
      .body("address.code", equalTo(123))
  }

  @Test
  fun `should return user by ID and verify with extract`(spec: RequestSpecification) {
    val foundUser = AppUser(
      id = "123",
      firstName = "Piotr",
      lastName = "Wolak",
      email = "contact@codersee.com",
      address = Address(
        street = "street",
        city = "city",
        code = 123
      )
    )

    every {
      repo.findById("123")
    } returns Optional.of(foundUser)

    val extracted = spec
      .whenever()
      .get("/users/123")
      .then()
      .statusCode(200)
      .extractAs(AppUser::class.java)

    assertEquals(foundUser, extracted)
  }

  @Test
  fun `should create a user`(spec: RequestSpecification) {
    val request = AppUserRequest(
      firstName = "Piotr",
      lastName = "Wolak",
      email = "contact@codersee.com",
      street = "Street",
      city = "City",
      code = 123,
    )

    val createdUser = AppUser(
      id = "123",
      firstName = "Piotr",
      lastName = "Wolak",
      email = "contact@codersee.com",
      address = Address(
        street = "street",
        city = "city",
        code = 123
      )
    )

    every {
      repo.save(any())
    } returns createdUser

    val extracted = spec
      .whenever()
      .contentType(ContentType.JSON)
      .body(request)
      .post("/users")
      .then()
      .statusCode(201)
      .extractAs(AppUser::class.java)

    assertEquals(createdUser, extracted)
  }

  @MockBean(AppUserRepository::class)
  fun appUserRepository(): AppUserRepository = repo
}</pre>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And that&#8217;s all for this tutorial on <strong>how to perform testing in Micronaut with Kotlin.</strong></p>



<p>Together, we&#8217;ve discovered a bunch of interesting things that I hope will be useful in your projects. </p>



<p>If you would like to see the codebase for this tutorial, then check out <a href="https://github.com/codersee-blog/kotlin-micronaut-testing" target="_blank" rel="noreferrer noopener">this GitHub repository</a>. Or, if you are interested in learning more about Micronaut, then check out <a href="https://blog.codersee.com/category/micronaut/">my other posts</a>. </p>



<p>Let me know your thoughts in the comments section below! 🙂 </p>
<p>The post <a href="https://blog.codersee.com/testing-micronaut-appplication-kotlin/">Testing Micronaut Application in Kotlin</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/testing-micronaut-appplication-kotlin/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Fix &#8220;Can&#8217;t find a codec for CodecCacheKey&#8221; in Micronaut</title>
		<link>https://blog.codersee.com/fix-cant-find-codec-for-codeccachekey-micronaut/</link>
					<comments>https://blog.codersee.com/fix-cant-find-codec-for-codeccachekey-micronaut/#respond</comments>
		
		<dc:creator><![CDATA[Piotr]]></dc:creator>
		<pubDate>Tue, 09 Jan 2024 16:15:00 +0000</pubDate>
				<category><![CDATA[Micronaut]]></category>
		<category><![CDATA[MongoDB]]></category>
		<category><![CDATA[Testing]]></category>
		<guid isPermaLink="false">https://codersee.com/?p=9508615</guid>

					<description><![CDATA[<p>In this short article, I will show you how to solve the "Unexpected error occurred: Can't find a codec for CodecCacheKey" in Micronaut. </p>
<p>The post <a href="https://blog.codersee.com/fix-cant-find-codec-for-codeccachekey-micronaut/">Fix &#8220;Can&#8217;t find a codec for CodecCacheKey&#8221; in Micronaut</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></description>
										<content:encoded><![CDATA[
<p>If you have ever struggled with the <strong><em>&#8220;Unexpected error occurred: Can&#8217;t find a codec for CodecCacheKey&#8221;</em></strong> when testing in <strong>Micronaut</strong>, then you came to the right place 🙂 </p>



<p>In this short article, I will show you how to fix this issue based on the example project. </p>



<h2 class="wp-block-heading" id="h-trigger-the-codeccachekey-in-micronaut-test">Trigger The CodecCacheKey in Micronaut Test</h2>



<p>Before I show you how to fix this issue, let me quickly introduce you to how I trigger the CodecCacheKey issue when writing tests in Micronaut. (If you are interested in the whole project, check <a href="https://blog.codersee.com/micronaut-with-mongodb-and-kotlin-revisited-2022/">this article about Micronaut with MongoDB</a>).</p>



<p>So firstly, I created a simple <code>AppUser</code> data class: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">import io.micronaut.data.annotation.GeneratedValue
import io.micronaut.data.annotation.Id
import io.micronaut.data.annotation.MappedEntity

@MappedEntity
data class AppUser(
  @field:Id
  @field:GeneratedValue
  val id: String? = null,
  val firstName: String,
  val lastName: String,
  val email: String,
  val address: Address
)</pre>



<p>Nothing spectacular. Just a simple class with a few annotations necessary to work with MongoDB and generate identifiers automatically. </p>



<p>As the next step, I added the repository, which looked, as follows: </p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@MongoRepository
interface AppUserRepository : CrudRepository&lt;AppUser, String> {
 
  // few methods 
}</pre>



<p>And all of that together with other classes that are not important in this tutorial, created a structure, like this: </p>



<figure class="wp-block-image aligncenter size-full is-resized"><img loading="lazy" decoding="async" width="323" height="408" src="http://blog.codersee.com/wp-content/uploads/2024/01/micronaut_mongodb_codeccachekey_project_structure.png" alt="Image presents the package structure of the backend Kotlin project created with Micronaut that was used to trigger the &quot;Can't find a codec for CodecCacheKey&quot; issue" class="wp-image-9508616" style="width:323px;height:auto" srcset="https://blog.codersee.com/wp-content/uploads/2024/01/micronaut_mongodb_codeccachekey_project_structure.png 323w, https://blog.codersee.com/wp-content/uploads/2024/01/micronaut_mongodb_codeccachekey_project_structure-238x300.png 238w" sizes="auto, (max-width: 323px) 100vw, 323px" /></figure>



<p>So, lastly, I added a simple test with <em>@MicronautTest</em>, <em>JUnit 5</em>, and <em>REST Assured</em> to test whether my REST endpoint returns users from the Mongo database:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="kotlin" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">@MicronautTest
class AppUserControllerTestWithoutMocking {

  @Test
  fun `should return 200 OK on GET users`(spec: RequestSpecification) {
    spec
      .`when`()
      .get("/users")
      .then()
      .statusCode(200)
      .header("Content-Type", "application/json")
  }
}</pre>



<p> As a result, instead of the beautiful, green icon indicating that everything is fine, <strong>I got the following:</strong> </p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">[io-executor-thread-1] ERROR i.m.http.server.RouteExecutor - Unexpected error occurred: Can't find a codec for CodecCacheKey{clazz=class com.codersee.model.AppUser, types=null}.
org.bson.codecs.configuration.CodecConfigurationException: Can't find a codec for CodecCacheKey{clazz=class com.codersee.model.AppUser, types=null}.
	at org.bson.internal.ProvidersCodecRegistry.lambda$get$0(ProvidersCodecRegistry.java:87)
	at java.base/java.util.Optional.orElseGet(Optional.java:364)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:80)
	at org.bson.internal.ProvidersCodecRegistry.get(ProvidersCodecRegistry.java:50)
	at com.mongodb.internal.operation.Operations.createFindOperation(Operations.java:188)
...</pre>



<p>Moreover, when I ran the application manually and tested using a real MongoDB instance, <strong>everything worked fine</strong>. </p>



<h2 class="wp-block-heading" id="h-how-to-fix-codeccachekey-issue">How To Fix CodecCacheKey Issue?</h2>



<p>In order to fix the issue, I created a new file- called <code>application-test.properties</code> in the <code>resources</code> directory and put the following:</p>



<pre class="EnlighterJSRAW" data-enlighter-language="raw" data-enlighter-theme="" data-enlighter-highlight="" data-enlighter-linenumbers="" data-enlighter-lineoffset="" data-enlighter-title="" data-enlighter-group="">mongodb.package-names=com.codersee.model</pre>



<p>But what exactly does it do? </p>



<p>Well, firstly, the application-test name of the file instructs the Micronaut framework to use this property file only when running tests. </p>



<p>Secondly, with the <code>mongodb.package-names</code>, I set package names to allow for POJOs. And that&#8217;s why I put the <code>com.codersee.model</code> only. </p>



<p>And voila, that&#8217;s all 🙂 </p>



<h2 class="wp-block-heading" id="h-summary">Summary</h2>



<p>And basically, that&#8217;s all for this short tutorial on how to fix the issue with CodecCacheKey in Micronaut. </p>



<p>Thank you for being here, and if you would like to learn more about the framework, then check out other posts from the <a href="https://blog.codersee.com/category/micronaut/">Micronaut category</a>. </p>



<p>If you would like to see the codebase for this tutorial, please refer to <a href="https://github.com/codersee-blog/micronaut-kotlin-mongodb-revisited" target="_blank" rel="noreferrer noopener">my GitHub repository</a>.</p>
<p>The post <a href="https://blog.codersee.com/fix-cant-find-codec-for-codeccachekey-micronaut/">Fix &#8220;Can&#8217;t find a codec for CodecCacheKey&#8221; in Micronaut</a> appeared first on <a href="https://blog.codersee.com">Codersee blog- Kotlin on the backend</a>.</p>
]]></content:encoded>
					
					<wfw:commentRss>https://blog.codersee.com/fix-cant-find-codec-for-codeccachekey-micronaut/feed/</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>

<!--
Performance optimized by W3 Total Cache. Learn more: https://www.boldgrid.com/w3-total-cache/?utm_source=w3tc&utm_medium=footer_comment&utm_campaign=free_plugin

Page Caching using Disk: Enhanced 

Served from: blog.codersee.com @ 2026-05-13 08:48:44 by W3 Total Cache
-->