0

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

@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插入样本数据。如何在运行测试之前确保应用程序成功启动。

完整的代码在这里

还有另一个用 Junit5 和 Mockito 编写的模拟示例,效果很好。

4

1 回答 1

0

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

第一个是Environment用于排除DataInitiliazerbean。

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

并使用环境运行测试mock

@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>()
}

第二种方法是在beanPostRepository中调用的 mocked 中的 mocking 方法。DataInitializer同时,注入EmbeddedServer并创建HttpClientbean 以确保端口可用。

@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;
    }
}
于 2021-10-21T08:40:44.980 回答