使用 Mockito 模拟具有泛型参数的类
是否有一种干净的方法来模拟带有泛型参数的类?假设我必须模拟一个 Foo
类,我需要将其传递到需要 Foo
的方法中。我可以很容易地执行以下操作:
Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
假设 getValue()
返回泛型类型 T
。但是,当我稍后将其传递到需要 Foo
的方法时,就会有小猫。铸造是做到这一点的唯一方法吗?
Is there a clean method of mocking a class with generic parameters? Say I have to mock a class Foo<T>
which I need to pass into a method that expects a Foo<Bar>
. I can do the following easily enough:
Foo mockFoo = mock(Foo.class);
when(mockFoo.getValue).thenReturn(new Bar());
Assuming getValue()
returns the generic type T
. But that's going to have kittens when I later pass it into a method expecting Foo<Bar>
. Is casting the only means of doing this?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(12)
我认为你确实需要投射它,但它应该不会太糟糕:
I think you do need to cast it, but it shouldn't be too bad:
另一种解决方法是使用
@Mock
注释。并非在所有情况下都有效,但看起来更性感:)
这是一个示例:
MockitoJUnitRunner
初始化用@Mock
。One other way around this is to use
@Mock
annotation instead.Doesn't work in all cases, but looks much sexier :)
Here's an example:
The
MockitoJUnitRunner
initializes the fields annotated with@Mock
.您始终可以创建一个中间类/接口来满足您想要指定的泛型类型。例如,如果 Foo 是一个接口,您可以在测试类中创建以下接口。
在 Foo 是非最终类的情况下,您可以使用以下代码扩展该类并执行相同的操作:
然后您可以使用以下代码使用上述示例之一:
You could always create an intermediate class/interface that would satisfy the generic type that you are wanting to specify. For example, if Foo was an interface, you could create the following interface in your test class.
In situations where Foo is a non-final class, you could just extend the class with the following code and do the same thing:
Then you could consume either of the above examples with the following code:
创建一个测试实用方法。如果您多次需要它,则特别有用。
Create a test utility method. Specially useful if you need it for more than once.
我同意不应抑制类或方法中的警告,因为人们可能会忽略其他意外抑制的警告。但恕我直言,抑制仅影响单行代码的警告是绝对合理的。
I agree that one shouldn't suppress warnings in classes or methods as one could overlook other, accidentally suppressed warnings. But IMHO it's absolutely reasonable to suppress a warning that affects only a single line of code.
对于 JUnit5,我认为最好的方法是在方法参数或字段中使用 @ExtendWith(MockitoExtension.class) 和 @Mock。
以下示例通过 Hamcrest 匹配器演示了这一点。
请参阅https://www.vogella.com/tutorials/Mockito/article.html 所需的 Maven/Gradle 依赖项。
With JUnit5 I think the best way is to @ExtendWith(MockitoExtension.class) with @Mock in the method parameter or the field.
The following example demonstrates that with Hamcrest matchers.
See https://www.vogella.com/tutorials/Mockito/article.html for the required Maven/Gradle dependencies.
正如其他答案所提到的,没有一个很好的方法来使用
mock()
& 。直接使用spy()
方法,无需不安全的泛型访问和/或抑制泛型警告。Mockito 项目中当前存在一个未解决的问题 (#1531),以添加对使用的支持
mock()
&没有泛型警告的spy()
方法。该问题于 2018 年 11 月提出,但没有任何迹象表明它会被优先处理。根据 Mockito 贡献者对此问题的评论之一:As the other answers mentioned, there's not a great way to use the
mock()
&spy()
methods directly without unsafe generics access and/or suppressing generics warnings.There is currently an open issue in the Mockito project (#1531) to add support for using the
mock()
&spy()
methods without generics warnings. The issue was opened in November 2018, but there aren't any indications that it will be prioritized. Per one of the Mockito contributor's comments on the issue:JUnit5
:在测试类上使用@ExtendWith(MockitoExtension.class)
,然后添加此字段:JUnit5
: use@ExtendWith(MockitoExtension.class)
on the test class then add this field:所以你有这个:
修复它的方法,从我最不喜欢到最喜欢:
@SuppressWarnings("unchecked")
注释。并不能真正解决问题,但您将不再收到警告。when
。So you have this:
Ways to fix it, starting from my least favourite to most:
@SuppressWarnings("unchecked")
annotation. Doesn't really fix it, but you'll stop getting the warnings.when
can be added in actual tests.这是一个有趣的案例:方法接收泛型集合并返回相同基类型的泛型集合。例如:
可以使用 Mockito anyCollectionOf 匹配器和答案的组合来模拟此方法。
Here is an interesting case: method receieves generic collection and returns generic collection of same base type. For example:
This method can be mocked with combination of Mockito anyCollectionOf matcher and the Answer.
(在我看来)最简单、最易读的方法是使用方法级注入。
这将导致测试方法中包含所有测试数据。这将使您的测试类保持干净,因为没有“浮动”模拟。
The (in my opinion) most easiest and most readable approach is to use method level injection.
This will result in having all test data within the test method. This will keep your test classes clean as there are no 'floating' mock's.
为什么不使用间谍
why not using spy