java Mock 不适用于新对象的创建
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/36995314/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Mock is not applied on new object creation
提问by being_uncertain
I was trying to mock a new object creation
我试图模拟一个新的对象创建
public class MyServiceTest {
MyClass myClass;
myClass = Mockito.mock(MyClass.class);
Mockito.when(new MyClass()).thenReturn(myClass);
}
Error:
错误:
org.mockito.exceptions.misusing.MissingMethodInvocationException:
when() requires an argument which has to be 'a method call on a mock'.
For example:
when(mock.getArticles()).thenReturn(articles);
Also, this error might show up because: 1. you stub either of: final/private/equals()/hashCode() methods. Those methods cannotbe stubbed/verified. Mocking methods declared on non-public parent classes is not supported. 2. inside when() you don't call method on mock but on some other object.
此外,出现此错误的原因可能是: 1. 您存根了以下任一方法: final/private/equals()/hashCode() 方法。这些方法不能被存根/验证。不支持在非公共父类上声明的模拟方法。2. 在 when() 中,您不会在模拟上调用方法,而是在其他对象上调用方法。
I did mock the myClass object, but it is getting assigned to a new object on method call:
我确实模拟了 myClass 对象,但它在方法调用时被分配给一个新对象:
public class MyService {
public static String myMethod(){
MyClass myClass = new MyClass();
//..........
}
}
回答by GhostCat
First: I recommend to not use PowerMock. As using this framework often results in bizarre errors, and: you have to understand that you are not facing a "deficiency" of Mockito ... but a deficiency in your design.
第一:我建议不要使用 PowerMock。因为使用这个框架经常会导致奇怪的错误,并且:你必须明白你面临的不是 Mockito 的“缺陷”......而是你的设计缺陷。
Basically, you want to learn about using dependency injection. The whole idea is: you do not call newwithin your production code. Because, you can't mock calling "new". Instead, you push the objects that your production code needs ... into your classes.
基本上,您想了解使用依赖注入。整个想法是:不要在生产代码中调用new。因为,你不能模拟调用“new”。相反,您将生产代码需要的对象推送到您的类中。
For normal (production) work, you push normal objects; and for unit testing, you push in mocked objects.
对于正常(生产)工作,您推送正常对象;对于单元测试,你推入模拟对象。
In other words: if you figure that your design would require PowerMock to be tested; then that tells you that your design needs to be reworked.
换句话说:如果您认为您的设计需要对 PowerMock 进行测试;那么这告诉你你的设计需要重新设计。
回答by Jeff Bowman
This is correct behavior; Mockito doesn't support mocking new object creation.You'll need another library like PowerMockfor that, or you'll need to refactor your test.
这是正确的行为;Mockito 不支持模拟新对象的创建。为此,您将需要另一个像PowerMock这样的库,或者您需要重构您的测试。
To learn a little more about each part of a Mockito-based test:
要了解有关基于 Mockito 的测试的每个部分的更多信息:
/* 1 */ MyObject myObjectMock = Mockito.mock(MyObject.class);
/* 2 */ when(myObjectMock.methodCall()).thenReturn("return value");
/* 3 */ MySystemUnderTest systemUnderTest = new MySystemUnderTest(myObjectMock);
/* 4 */ systemUnderTest.methodToTest();
/* 5 */ verify(myObjectMock).methodCalledByTheSystemUnderTest();
mock
creates a mock object. Note that you're not setting expectations on all instances of MyObject; instead, you're creating a single instance to control. Internally, this is actually a one-off subclass of MyObject with all its methods overridden, so Mockito is only really good for visible non-final instance methods(that you could override yourself).You can use the
when
call to stubbehavior. The only thing that can go insidewhen
is a single call to a method on a Mockito-created mock, so yournew
keyword won't work here.Again, because you can't use
new
, you'll generally need to insert your mock into your system under test. You (almost) never mock the system under test; you're mocking the collaborator instead, and since you can't usenew
you generally have to pass it in. This is part of why Mockito works so well with dependency injection systems.Then you call your method-under-test...
...and check that the final state is what you want it to be. This can be assertions like
assertEquals
from a test framework, calls toverify
using Mockito-created mocks, or some combination of the two.
mock
创建一个模拟对象。请注意,您并未对 MyObject 的所有实例设置期望值;相反,您正在创建要控制的单个实例。在内部,这实际上是 MyObject 的一次性子类,其所有方法都被覆盖,因此 Mockito 仅适用于可见的非最终实例方法(您可以自己覆盖)。您可以使用
when
对存根行为的调用。唯一可以进入内部的when
是对 Mockito 创建的 mock 上的方法的单次调用,因此您的new
关键字在这里不起作用。同样,因为您不能使用
new
,您通常需要将您的模拟插入到您的被测系统中。你(几乎)从不嘲笑被测系统;你正在嘲笑合作者,因为你不能使用new
你通常必须将它传递进来。这就是为什么 Mockito 在依赖注入系统中工作得如此出色的部分原因。然后你调用你的被测方法......
...并检查最终状态是否是您想要的状态。这可以是
assertEquals
来自测试框架的断言,调用verify
使用 Mockito 创建的模拟,或两者的某种组合。
Remember, with just Mockito, you will not be able to have Java return a mock when calling new
, so you'll need a step like step 3 above. Alternatively, PowerMockis an extension library on top of EasyMock or Mockito, which has static methods like whenNew
and mockStatic
for more advanced mocking. (A word of caution, though: Because PowerMock uses a special classloader to rewrite your classes, it can be more difficult to set up, and its magic may make your tests harder to reason about. Refactoring may be a better way to keep your tests understandable.)
请记住,仅使用 Mockito,您将无法在调用new
时让Java 返回模拟,因此您需要执行类似于上述第 3 步的步骤。或者,PowerMock是 EasyMock 或 Mockito 之上的扩展库,它具有静态方法,例如whenNew
和mockStatic
用于更高级的模拟。(不过,请注意:由于 PowerMock 使用特殊的类加载器来重写您的类,因此设置起来可能会更加困难,而且它的魔力可能会使您的测试更难推理。重构可能是保持测试的更好方法可以理解。)
回答by AdZzZ
You can try powermock. It worked for me.
你可以试试powermock。它对我有用。
import org.powermock.api.mockito.PowerMockito;
MyClass myClassMock = Mockito.spy(new MyClass());
PowerMockito.whenNew(MyClass.class).withNoArguments().thenReturn(myClassMock);