【问题标题】:How to mock a bean in a test written in Micronaut Kotest如何在用 Micronaut Kotest 编写的测试中模拟 bean
【发布时间】:2021-10-20 11:07:34
【问题描述】:

我正在尝试添加测试以测试控制器,但模拟依赖项。

@MicronautTest
class PostControllerTest(private val posts: PostRepository, @Client("/") private val client: HttpClient) : StringSpec({

    "test get posts endpoint" {
        every { posts.findAll() }
            .returns(
                listOf(
                    Post(
                        id = UUID.randomUUID(),
                        title = "test title",
                        content = "test content",
                        status = Status.DRAFT,
                        createdAt = LocalDateTime.now()
                    )
                )
            )
        val request = HttpRequest.GET<Any>("/posts")
        val bodyType = Argument.listOf(Post::class.java).type
        val response = client.toBlocking().exchange(request, bodyType)

        response.status shouldBe HttpStatus.OK
        response.body()!![0].title shouldBe "test title"

        verify(exactly = 1) { posts.findAll() }
    }

    @MockBean(PostRepository::class)
    fun posts() = mockk<PostRepository>()
})

这不起作用,因为无法识别模拟的PostRepsoitory

运行测试时更改为以下内容。

@MicronautTest
class PostControllerTest(
    private val postsBean: PostRepository,
    @Client("/") private var client: HttpClient
) : FunSpec({

    test("test get posts endpoint") {
        val posts = getMock(postsBean)
        every { posts.findAll() }
            .returns(
                listOf(
                    Post(
                        id = UUID.randomUUID(),
                        title = "test title",
                        content = "test content",
                        status = Status.DRAFT,
                        createdAt = LocalDateTime.now()
                    )
                )
            )
        val request = HttpRequest.GET<Any>("/posts")
        val bodyType = Argument.listOf(Post::class.java).type
        val response = client.toBlocking().exchange(request, bodyType)

        response.status shouldBe HttpStatus.OK
        response.body()!![0].title shouldBe "test title"

        verify(exactly = 1) { posts.findAll() }
    }
}) {
    @MockBean(PostRepository::class)
    fun posts() = mockk<PostRepository>()
}

得到了这样的异常。

io.micronaut.context.exceptions.BeanInstantiationException: Error instantiating bean of type  [com.example.PostControllerTest]

Message: Retrieving the port from the server before it has started is not supported when binding to a random port
Path Taken: new DataInitializer(PostRepository posts) --> new DataInitializer([PostRepository posts]) --> new PostControllerTest(PostRepository postsBean,[HttpClient client])

DataInitializer 用于监听StartupEvent 并插入样本数据。如何在运行测试之前确保应用程序已成功启动。

完整代码为here

another mock example written in Junit5 and Mockito,很好用。

【问题讨论】:

    标签: micronaut mockk micronaut-data kotest


    【解决方案1】:

    最后我发现有两种方法可以克服这个障碍。

    第一个是使用Environment 排除DataInitiliazer bean。

    @Requires(notEnv=["mock"])
    class DataInitiliazer...
    
    

    并使用mock env 运行测试。

    @MicronautTest(environments = ["mock"])
    class PostControllerTest(
        private val postsBean: PostRepository,
        @Client("/") private var client: HttpClient
    ) : FunSpec({
    
    
        test("test get posts endpoint") {
            val posts = getMock(postsBean)
            every { posts.findAll() }
                .returns(
                    listOf(
                        Post(
                            id = UUID.randomUUID(),
                            title = "test title",
                            content = "test content",
                            status = Status.DRAFT,
                            createdAt = LocalDateTime.now()
                        )
                    )
                )
            val response = client.toBlocking().exchange("/posts", Array<Post>::class.java)
    
            response.status shouldBe HttpStatus.OK
            response.body()!![0].title shouldBe "test title"
    
            verify(exactly = 1) { posts.findAll() }
        }
    }) {
        @MockBean(PostRepository::class)
        fun posts() = mockk<PostRepository>()
    }
    

    第二种方法是模拟 PostRepository 中的模拟方法,这些方法将在 DataInitializer bean 中调用。同时,注入EmbeddedServer 并创建HttpClient bean 以确保端口可用。

    @MicronautTest()
    class PostControllerTest(
       private val server: EmbeddedServer,
    ) : FunSpec({
    
        test("test the server is running") {
            assert(server.isRunning)
        }
    
        test("test get posts endpoint") {
            val postsBean = server.applicationContext.getBean(PostRepository::class.java)
            val client = server.applicationContext.createBean(HttpClient::class.java, server.url)
            val posts = getMock(postsBean)
            every { posts.findAll() }
                .returns(
                    listOf(
                        Post(
                            id = UUID.randomUUID(),
                            title = "test title",
                            content = "test content",
                            status = Status.DRAFT,
                            createdAt = LocalDateTime.now()
                        )
                    )
                )
            val response = client.toBlocking().exchange("/posts", Array<Post>::class.java)
    
            response.status shouldBe HttpStatus.OK
            response.body()!![0].title shouldBe "test title"
    
            verify(exactly = 1) { posts.findAll() }
        }
    }) {
        @MockBean(PostRepository::class)
        fun posts(): PostRepository {
            val mock = mockk<PostRepository>()
            justRun { mock.deleteAll() }
            every { mock.saveAll(any<List<Post>>()) } returns listOf<Post>()
            return mock;
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2011-07-20
      • 1970-01-01
      • 1970-01-01
      • 2019-10-20
      • 2020-10-10
      • 1970-01-01
      • 1970-01-01
      • 2022-08-11
      相关资源
      最近更新 更多