Mockito 如何仅模拟超类方法的调用
我在一些测试中使用 Mockito。
我有以下类:
class BaseService {
public void save() {...}
}
public Childservice extends BaseService {
public void save(){
//some code
super.save();
}
}
我只想模拟 ChildService
的第二次调用 (super.save
)。第一次调用必须调用真正的方法。有办法做到这一点吗?
I'm using Mockito in some tests.
I have the following classes:
class BaseService {
public void save() {...}
}
public Childservice extends BaseService {
public void save(){
//some code
super.save();
}
}
I want to mock only the second call (super.save
) of ChildService
. The first call must call the real method. Is there a way to do that?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(11)
就我而言,我创建了一个新方法来包装超类的方法并进行测试替身。因为当我实现 oAuth2 客户端时,我需要来自超类方法的结果。我希望这个答案对需要使用超类方法结果的人有帮助。
被测系统
loadUserFromParent
方法来包装超类函数测试
doReturn(expectedValue).when(testDouble).method(params)
In my case, I make a new method to wrap super class's method and make a test double. Because I need result from super class method when I implement oAuth2 client. I want this answer is helpful who someone needs to use result from super class's method.
System Under Test
loadUserFromParent
method to wrap super class functionTest
doReturn(expectedValue).when(testDouble).method(params)
有一种适用于大多数情况的简单方法。您可以监视您的对象并存根您想要模拟的方法。
这是一个示例:
因此,当您测试对象时,可以使用 myObjectSpy ,并且当调用 methodToMock 时,它将通过模拟方法覆盖正常行为。
此代码用于带返回的方法。如果您有一个 void 方法,您可以使用 什么都不做 代替。
There is simple approach that works for most of cases. You can spy your object and stub the method you want to mock.
Here is an example:
So, when you test your object, you can use myObjectSpy and when methodToMock is called, it will overwrite the normal behavior by a mock method.
This code for a method with return. In case you have a void method you can use doNothing instead.
您可以使用 PowerMockito 来执行此操作,并通过继续测试子类方法来仅替换父类方法的行为。即使该方法返回某个值(假设是一个字符串),您也可以执行以下操作:
如果您没有返回任何值 (
void
),则可以使用doReturn
来代替什么也不做
。如果方法有一些参数,则添加一些optionalArgs
,如果没有,则跳过该部分。You can do this with PowerMockito and replace behavior only of the parent class method with continuing testing the child's class method. Even when the method is returning some value, lets say a string, you can do something like this:
If you are returning nothing (
void
) then instead ofdoReturn
you can usedoNothing
. Add someoptionalArgs
if the method have some arguments, if not, then skip that part.原因是你的基类不是公共的,那么Mockito由于可见性而无法拦截它,如果你将基类更改为公共,或者在子类中@Override(公共),那么Mockito可以正确模拟它。
The reason is your base class is not public-ed, then Mockito cannot intercept it due to visibility, if you change base class as public, or @Override in sub class (as public), then Mockito can mock it correctly.
我找到了一种使用 PowerMockito 抑制超类方法的方法。 需要3个简单的步骤
使用PowerMockito.suppress方法和MemberMatcher.methodsDeclaredIn方法来抑制父类方法
第二个在@PrepareForTest中添加父类
使用PowerMock运行测试类,即在测试类上方添加@RunWith(PowerMockRunner.class)。
注意:只有当超类方法不返回任何内容时,这才有效。
I found a way to suppress the superclass method using PowerMockito. 3 simple steps need for this
Use PowerMockito.suppress method and MemberMatcher.methodsDeclaredIn method to supress parent class method
Second add Parent class in @PrepareForTest
Run your test class with PowerMock ie add @RunWith(PowerMockRunner.class) above your test class.
Note: This will work only when the superclass method does not return anything.
如果继承有意义,也许最简单的选择是创建一个新方法(包私有?)来调用 super(让我们称之为 superFindall),监视真实实例,然后以您想要模拟的方式模拟 superFindAll() 方法家长一班。就覆盖范围和可见性而言,它不是完美的解决方案,但它应该可以完成工作并且易于应用。
Maybe the easiest option if inheritance makes sense is to create a new method (package private??) to call the super (lets call it superFindall), spy the real instance and then mock the superFindAll() method in the way you wanted to mock the parent class one. It's not the perfect solution in terms of coverage and visibility but it should do the job and it's easy to apply.
在调用超类方法的子类中创建一个受包保护(假设测试类位于同一包中)的方法,然后在重写的子类方法中调用该方法。然后,您可以通过使用间谍模式在测试中设置对此方法的期望。不太漂亮,但肯定比在测试中处理 super 方法的所有期望设置要好
create a package protected (assumes test class in same package) method in the sub class that calls the super class method and then call that method in your overridden sub class method. you can then set expectations on this method in your test through the use of the spy pattern. not pretty but certainly better than having to deal with all the expectation setting for the super method in your test
即使我完全同意 iwein 的回应(
),我承认有时继承似乎很自然,并且我不觉得只是为了单元测试而破坏或重构它。
所以,我的建议:
然后,在单元测试中:
Even if i totally agree with iwein response (
), i admit there are some times inheritance seems just natural, and i don't feel breaking or refactor it just for the sake of a unit test.
So, my suggestion :
And then, in the unit test :
如果您确实没有重构的选择,您可以模拟/存根超级方法调用中的所有内容,例如
If you really don't have a choice for refactoring you can mock/stub everything in the super method call e.g.
不,Mockito 不支持这一点。
这可能不是您正在寻找的答案,但您看到的是不应用设计原则的症状:
如果您提取策略而不是扩展超类,那么问题就消失了。
然而,如果你不被允许更改代码,但无论如何你必须测试它,并且以这种尴尬的方式,仍然有希望。使用一些 AOP 工具(例如 AspectJ),您可以将代码编织到超类方法中并完全避免其执行(恶心)。如果您使用代理,则这不起作用,您必须使用字节码修改(加载时编织或编译时编织)。还有一些模拟框架也支持这种类型的技巧,例如 PowerMock 和 PowerMockito。
我建议你进行重构,但如果这不是一个选择,你就会享受一些严肃的黑客乐趣。
No, Mockito does not support this.
This might not be the answer you're looking for, but what you're seeing is a symptom of not applying the design principle:
If you extract a strategy instead of extending a super class the problem is gone.
If however you are not allowed to change the code, but you must test it anyway, and in this awkward way, there is still hope. With some AOP tools (for example AspectJ) you can weave code into the super class method and avoid its execution entirely (yuck). This doesn't work if you're using proxies, you have to use bytecode modification (either load time weaving or compile time weaving). There are be mocking frameworks that support this type of trick as well, like PowerMock and PowerMockito.
I suggest you go for the refactoring, but if that is not an option you're in for some serious hacking fun.
考虑将代码从 ChildService.save() 方法重构为不同的方法,并测试新方法而不是测试 ChildService.save(),这样您将避免不必要的超级方法调用。
例子:
Consider refactoring the code from ChildService.save() method to different method and test that new method instead of testing ChildService.save(), this way you will avoid unnecessary call to super method.
Example: