<?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>REST Assured Archives - Codersee blog- Kotlin on the backend</title>
	<atom:link href="https://blog.codersee.com/tag/rest-assured/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:36 +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>REST Assured Archives - Codersee blog- Kotlin on the backend</title>
	<link></link>
	<width>32</width>
	<height>32</height>
</image> 
	<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>
	</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-18 15:04:09 by W3 Total Cache
-->