Java Mockito:如何验证在方法中创建的对象上调用了方法?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9841623/
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
Mockito : how to verify method was called on an object created within a method?
提问by mre
I am new to Mockito.
我是 Mockito 的新手。
Given the class below, how can I use Mockito to verify that someMethod
was invoked exactly once after foo
was invoked?
鉴于下面的类,我如何使用 Mockito 来验证在someMethod
被调用后恰好被调用一次foo
?
public class Foo
{
public void foo(){
Bar bar = new Bar();
bar.someMethod();
}
}
I would like to make the following verification call,
我想拨打以下验证电话,
verify(bar, times(1)).someMethod();
where bar
is a mocked instance of Bar
.
bar
的模拟实例在哪里Bar
?
采纳答案by csturtz
If you inject the Bar instance, or a factory that is used for creating the Bar instance (or one of the other 483 ways of doing this), you'd have the access necessary to do perform the test.
如果您注入 Bar 实例或用于创建 Bar 实例的工厂(或执行此操作的其他 483 种方法之一),您将拥有执行测试所需的访问权限。
Factory Example:
工厂示例:
Given a Foo class written like this:
给定一个像这样写的 Foo 类:
public class Foo {
private BarFactory barFactory;
public Foo(BarFactory factory) {
this.barFactory = factory;
}
public void foo() {
Bar bar = this.barFactory.createBar();
bar.someMethod();
}
}
in your test method you can inject a BarFactory like this:
在您的测试方法中,您可以像这样注入 BarFactory:
@Test
public void testDoFoo() {
Bar bar = mock(Bar.class);
BarFactory myFactory = new BarFactory() {
public Bar createBar() { return bar;}
};
Foo foo = new Foo(myFactory);
foo.foo();
verify(bar, times(1)).someMethod();
}
Bonus: This is an example of how TDD can drive the design of your code.
奖励:这是 TDD 如何驱动代码设计的示例。
回答by Michael Brewer-Davis
The classic response is, "You don't." You test the public API of Foo
, not its internals.
经典的回答是,“你没有。” 您测试的是 的公共 API Foo
,而不是其内部。
Is there any behavior of the Foo
object (or, less good, some other object in the environment) that is affected by foo()
? If so, test that. And if not, what does the method do?
是否存在受 影响的Foo
对象(或环境中的其他对象)的任何行为foo()
?如果是这样,测试一下。如果没有,该方法有什么作用?
回答by John B
Yes, if you really want / need to do it you can use PowerMock. This should be considered a last resort. With PowerMock you can cause it to return a mock from the call to the constructor. Then do the verify on the mock. That said, csturtz's is the "right" answer.
是的,如果您真的想要/需要这样做,您可以使用 PowerMock。这应该被视为最后的手段。使用 PowerMock,您可以使其从对构造函数的调用返回模拟。然后在模拟上进行验证。也就是说,csturtz 是“正确”的答案。
Here is the link to Mock construction of new objects
这是新对象的模拟构造的链接
回答by raspacorp
If you don't want to use DI or Factories. You can refactor your class in a little tricky way:
如果您不想使用 DI 或工厂。你可以用一种有点棘手的方式重构你的类:
public class Foo {
private Bar bar;
public void foo(Bar bar){
this.bar = (bar != null) ? bar : new Bar();
bar.someMethod();
this.bar = null; // for simulating local scope
}
}
And your test class:
还有你的测试课:
@RunWith(MockitoJUnitRunner.class)
public class FooTest {
@Mock Bar barMock;
Foo foo;
@Test
public void testFoo() {
foo = new Foo();
foo.foo(barMock);
verify(barMock, times(1)).someMethod();
}
}
Then the class that is calling your foo method will do it like this:
然后调用你的 foo 方法的类会这样做:
public class thirdClass {
public void someOtherMethod() {
Foo myFoo = new Foo();
myFoo.foo(null);
}
}
As you can see when calling the method this way, you don't need to import the Bar class in any other class that is calling your foo method which is maybe something you want.
正如您在以这种方式调用方法时所看到的那样,您不需要在调用 foo 方法的任何其他类中导入 Bar 类,这可能是您想要的。
Of course the downside is that you are allowing the caller to set the Bar Object.
当然,缺点是您允许调用者设置 Bar 对象。
Hope it helps.
希望能帮助到你。
回答by javaPlease42
Solution for your example code using PowerMockito.whenNew
使用示例代码的解决方案 PowerMockito.whenNew
- mockito-all 1.10.8
- powermock-core 1.6.1
- powermock-module-junit4 1.6.1
- powermock-api-mockito 1.6.1
- junit 4.12
- mockito-all 1.10.8
- powermock 核心 1.6.1
- powermock-module-junit4 1.6.1
- powermock-api-mockito 1.6.1
- 联合 4.12
FooTest.java
测试文件
package foo;
import org.junit.After;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.Mockito;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;
//Both @PrepareForTest and @RunWith are needed for `whenNew` to work
@RunWith(PowerMockRunner.class)
@PrepareForTest({ Foo.class })
public class FooTest {
// Class Under Test
Foo cut;
@Mock
Bar barMock;
@Before
public void setUp() throws Exception {
cut = new Foo();
}
@After
public void tearDown() {
cut = null;
}
@Test
public void testFoo() throws Exception {
// Setup
PowerMockito.whenNew(Bar.class).withNoArguments()
.thenReturn(this.barMock);
// Test
cut.foo();
// Validations
Mockito.verify(this.barMock, Mockito.times(1)).someMethod();
}
}
回答by siulkilulki
I think Mockito @InjectMocks
is the way to go.
我认为 Mockito@InjectMocks
是要走的路。
Depending on your intention you can use:
根据您的意图,您可以使用:
- Constructor injection
- Property setter injection
- Field injection
- 构造函数注入
- 属性设置器注入
- 现场注入
More info in docs
文档中的更多信息
Below is an example with field injection:
下面是一个带有字段注入的示例:
Classes:
课程:
public class Foo
{
private Bar bar = new Bar();
public void foo()
{
bar.someMethod();
}
}
public class Bar
{
public void someMethod()
{
//something
}
}
Test:
测试:
@RunWith(MockitoJUnitRunner.class)
public class FooTest
{
@Mock
Bar bar;
@InjectMocks
Foo foo;
@Test
public void FooTest()
{
doNothing().when( bar ).someMethod();
foo.foo();
verify(bar, times(1)).someMethod();
}
}
回答by Nestor Milyaev
Another simple way would be add some log statement to the bar.someMethod() and then ascertain you can see the said message when your test executed, see examples here: How to do a JUnit assert on a message in a logger
另一种简单的方法是向 bar.someMethod() 添加一些日志语句,然后确定您在测试执行时可以看到所述消息,请参见此处的示例:如何对记录器中的消息执行 JUnit 断言
That is especially handy when your Bar.someMethod() is private
.
当您的 Bar.someMethod() 是private
.