无法在 Kotlin 中使用 Optional 模拟 `willReturn`

Can't mock `willReturn` with Optional in Kotlin

我有办法

fun getUser(userId: UserId): Optional<User?> = userRepository.findById(userId)

returns Java 中的可选。 所以我想在我的 Kotlin 单元测试中模拟该方法调用。

这是我的第一个猜测...

given { mockedUserService.getUser(currentUser.userId) }.willReturn(Optional.of(currentUser))

...但是编译器说不

Type mismatch: inferred type is Optional but Optional<User?>! was expected

所以我开始制作 val currentUser: User? 只是为了让编译器开心。

given { currentUser?.userId?.let { mockedUserService.getUser(it) }.willReturn(Optional.of(currentUser))

Type mismatch: inferred type is Optional but Optional<User?>? was expected

Type mismatch: inferred type is User? but TypeVariable(T) was expected

现在我有些迷茫了。我怎样才能让编译器开心?

您可以尝试 willAnswer 而不是 willReturn:

given { mockedUserService.getUser(currentUser.userId) }.willAnswer { Optional.of(currentUser) }

考虑将此作为替代方案。我假设你正在使用 Java 的类型 Optional 而不是你自己的实现(做的比我在这里看到的更多)。

Optional 来到 Java 以避免 NPE 并指示在运行时缺少类型。但是在 Kotlin 中你并不真的需要一个 Optional,因为你可以明确地定义你的类型为 nullable T?.

因此您可以将其定义为:

fun getUser(userId: UserId): User?

fun getUser(userId: UserId): Optional<User> // not nullable!

一种方法是修复测试,但这实际上不是这里的问题。在 Kotlin 中,您应该尽可能避免使用 Optional。 Java 的类型系统无法区分可空值和不可空值。 Kotlin 有,所以你应该尽早将 Optional<T> 转换为 T?.

您可以像这样轻松修复您的功能:

fun getUser(userId: UserId): User? = userRepository.findById(userId).orElse(null)