Mockito:使用有界通配符返回类型的存根方法
考虑以下代码:
public class DummyClass {
public List<? extends Number> dummyMethod() {
return new ArrayList<Integer>();
}
}
public class DummyClassTest {
public void testMockitoWithGenerics() {
DummyClass dummyClass = Mockito.mock(DummyClass.class);
List<? extends Number> someList = new ArrayList<Integer>();
Mockito.when(dummyClass.dummyMethod()).thenReturn(someList); //Compiler complains about this
}
}
编译器抱怨试图对 dummyMethod()
的行为进行存根的行。有关如何处理返回带有有界通配符的类型的存根方法的任何指示吗?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(6)
您还可以使用非类型安全方法 doReturn 为此目的,
如 在 Mockito 的 google 上讨论团体。
虽然这比 thenAnswer 更简单,但请再次注意,它不是类型安全的。如果您担心类型安全,millhouse 的答案是正确的。
其他详细信息
需要明确的是,这里是观察到的编译器错误,
我相信编译器在
when
调用期间分配了第一个通配符类型,然后无法确认thenReturn
调用中的第二个通配符类型是相同的。看起来
thenAnswer
不会遇到此问题,因为它接受通配符类型,而thenReturn
则采用非通配符类型,必须捕获该类型。来自 Mockito 的 正在进行的存根,You can also use the non-type safe method doReturn for this purpose,
as discussed on Mockito's google group.
While this is simpler than
thenAnswer
, again note that it is not type safe. If you're concerned about type safety, millhouse's answer is correct.Additional Details
To be clear, here's the observed compiler error,
I believe the compiler has assigned the first wildcard type during the
when
call and then cannot confirm that the second wildcard type in thethenReturn
call is the same.It looks like
thenAnswer
doesn't run into this issue because it accepts a wildcard type whilethenReturn
takes a non-wildcard type, which must be captured. From Mockito's OngoingStubbing,我假设您希望能够加载一些已知值的
someList
;这是一种使用Answer
和模板化辅助方法来保持所有内容类型安全的方法:I'm assuming you want to be able to load up
someList
with some known values; here's an approach that usesAnswer<T>
together with a templated helper method to keep everything type-safe:我昨天也碰到同样的事情。 @nondescript1 和 @millhouse 的回答都帮助我找到了解决方法。我几乎使用了与 @millhouse 相同的代码,只是我让它稍微更通用一些,因为我的错误不是由
java.util.List
引起的,而是由com 引起的.google.common.base.可选
。因此,我的小辅助方法允许任何类型T
而不仅仅是List
:使用此辅助方法,您可以编写:
这编译得很好,并且执行与
thenReturn(...)
方法。有人知道 Java 编译器发出的错误是编译器错误还是代码确实不正确?
I hit the same thing yesterday. Both answers from @nondescript1 and @millhouse helped me to figure out a workaround. I've pretty much used the same code as @millhouse, except that I made it slightly more generic, because my error wasn't caused by a
java.util.List
, but thecom.google.common.base.Optional
. My little helper method therefore allows for any typeT
and not justList<T>
:With this helper method you could write:
This compiles just fine and does the same thing as the
thenReturn(...)
method.Does someone know if the error that the Java compiler emits is a compiler bug or if the code is really incorrect?
我正在转向fikovnik 的评论 放入此处的答案中,以使其更具可见性,因为我认为这是使用 Java 8+ 的最优雅的解决方案。
Mockito 文档建议仅将
doReturn()
(如已接受答案中的建议)用作最后的手段。相反,为了规避问题中描述的编译器错误,推荐的 Mockito
when()
方法可以与thenAnswer()
和 lambda (而不是辅助方法)一起使用:I'm turning fikovnik's comment into an answer here to give it more visibility as I think it's the most elegant solution using Java 8+.
The Mockito documentation recommends using
doReturn()
(as suggested in the accepted answer) only as a last resort.Instead, to circumevent the compiler error described in the question, the recommended Mockito
when()
approach can be used withthenAnswer()
and a lambda (instead of a helper method):尽管 Marek Radonsky 提出的实用方法有效,但还有另一种选择,甚至不需要 fikovnik 建议的(恕我直言,看起来很奇怪)lambda 表达式:
如 这个类似问题的答案显示,您还可以使用以下内容:
Although the utility method proposed by Marek Radonsky works, there is also an other option which doesn't even require the (IMHO strange looking) lambda expression fikovnik suggested:
As this answer to a similar question shows, you can also use the following:
删除<代码>?从您的 DummyClass 返回类型扩展 。
不合规代码示例:
合规解决方案
注意:
List.copyOf()
实现是高性能的如果您的集合是使用 List 创建的.of、Stream.toList 等,有效地进行强制转换而不是真正的副本。查看其源代码: src 1,src 2 。理由:使用通配符,例如
是一个关键的“Code Smell”。因为会迫使您的客户端代码与通配符类型声明作斗争,就像您使用 Mockito 的示例一样。
参考文献:
Remove
? extends
from your DummyClass return type.Noncompliant Code Example:
Compliant Solution
NOTE:
List.copyOf()
implementation is performant if your collection is created with List.of, Stream.toList, etc., effectively doing a cast rather than a real copy. See its source code: src 1, src 2.JUSTIFICATION: Using a wildcard like
<? extends Number>
in the return type is a critical "Code Smell". Because would force your client code to struggle with wildcard-type declarations, as in your example with Mockito.REFERENCEs: