我是新来的。给定下面的类,我如何使用Mockito来验证someMethod在foo被调用后被调用了一次?
someMethod
foo
public class Foo{ public void foo(){ Bar bar = new Bar(); bar.someMethod(); }}
public class Foo
{
public void foo(){
Bar bar = new Bar();
bar.someMethod();
}
字符串我想打个电话确认一下,
verify(bar, times(1)).someMethod();
型其中bar是Bar的模拟示例。
bar
Bar
ltqd579y1#
Dependency Injection如果您注入Bar示例,或用于创建Bar示例的工厂(或其他483种方法之一),您将拥有执行测试所需的访问权限。工厂示例:给定一个这样写的Foo类:
public class Foo { private BarFactory barFactory; public Foo(BarFactory factory) { this.barFactory = factory; } public void foo() { Bar bar = this.barFactory.createBar(); bar.someMethod(); }}
public class Foo {
private BarFactory barFactory;
public Foo(BarFactory factory) {
this.barFactory = factory;
public void foo() {
Bar bar = this.barFactory.createBar();
字符串在你的测试方法中,你可以像这样注入一个BarFactory:
@Testpublic 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();}
@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();
型奖励:这是一个TDD(测试驱动开发)如何驱动代码设计的例子。
eni9jsuy2#
经典的回答是“您不需要”。您测试的是Foo的公共API,而不是其内部。Foo对象(或者环境中的其他对象)的行为是否受到foo()的影响?如果是,测试它。如果不是,该方法做什么?
Foo
foo()
js81xvg63#
我认为Mockito @InjectMocks是一条正确的路。根据您的意图,您可以使用:用途:1.构造函数注入1.属性设置器注入1.现场注入更多信息docs下面是一个现场注入的例子:类别:
@InjectMocks
public class Foo{ private Bar bar = new Bar(); public void foo() { bar.someMethod(); }}public class Bar{ public void someMethod() { //something }}
private Bar bar = new Bar();
public void foo()
public class Bar
public void someMethod()
//something
字符串试验项目:
@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(); }}
@RunWith(MockitoJUnitRunner.class)
public class FooTest
@Mock
Bar bar;
Foo foo;
public void FooTest()
doNothing().when( bar ).someMethod();
型
eeq64g8w4#
如果你不想使用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 }}
private Bar bar;
public void foo(Bar bar){
this.bar = (bar != null) ? bar : new Bar();
this.bar = null; // for simulating local scope
字符串你的测试类:
@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(); }}
public class FooTest {
@Mock Bar barMock;
public void testFoo() {
foo = new Foo();
foo.foo(barMock);
verify(barMock, times(1)).someMethod();
型然后调用你的foo方法的类会这样做:
public class thirdClass { public void someOtherMethod() { Foo myFoo = new Foo(); myFoo.foo(null); }}
public class thirdClass {
public void someOtherMethod() {
Foo myFoo = new Foo();
myFoo.foo(null);
型正如你所看到的,当以这种方式调用方法时,你不需要在调用你的foo方法的任何其他类中导入Bar类,这可能是你想要的。当然,缺点是允许调用者设置Bar对象。希望对你有帮助。
dgiusagp5#
使用PowerMockito.whenNew的示例代码的解决方案
PowerMockito.whenNew
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(); }}
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 })
// Class Under Test
Foo cut;
Bar barMock;
@Before
public void setUp() throws Exception {
cut = new Foo();
@After
public void tearDown() {
cut = null;
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();
字符串
JUnit输出x1c 0d1x
cig3rfwq6#
是的,如果你真的想/需要这样做,你可以使用PowerMock。这应该被认为是最后的手段。使用PowerMock,你可以使它从对构造函数的调用中返回一个mock。然后对mock进行验证。也就是说,csturtz的是“正确”的答案。这里是Mock construction of new objects的链接
puruo6ea7#
我今天遇到了这个问题,我不想使用PowerMock或其他东西。我只是想做一个测试,以确保某个方法被调用。我找到了这篇文章,我看到没有人提到这种方法。实现这一点的一种方法是不添加更多的依赖项或类似的技术,但它是有效的:
@Testpublic void testSomeMethodIsCalledOnce() throws Exception { final AtomicInteger counter = new AtomicInteger(0); Mockito.when(someObject.theMethodIWant(anyString())) .then((Answer<ReturnValue>) __ -> { counter.incrementAndGet(); return theExpectedAnswer; }); theObjectUnderTest.theMethod(someTestValue); assertEquals(1, counter.get());}
public void testSomeMethodIsCalledOnce() throws Exception {
final AtomicInteger counter = new AtomicInteger(0);
Mockito.when(someObject.theMethodIWant(anyString()))
.then((Answer<ReturnValue>) __ -> {
counter.incrementAndGet();
return theExpectedAnswer;
});
theObjectUnderTest.theMethod(someTestValue);
assertEquals(1, counter.get());
字符串这很简单,很容易看出发生了什么。当我想要的方法被调用时(这里是模仿的),做这些事情。这些事情中有一个对AtomicallyIncrementAndGet的调用。你可以在这里使用int[],但在我看来这不是很清楚。我们只是使用了final的东西,我们可以递增。这是我们使用的lambda的限制。这有点粗糙,但它可以简单直接地完成工作。至少如果你知道你的Brachdas和Mockito。
x7yiwoj48#
另一种简单的方法是在bar.someMethod()中添加一些log语句,然后确定在执行测试时可以看到所述消息,请参见此处的示例:How to do a JUnit assert on a message in a logger当您的Bar.someMethod()是private时,这特别方便。
private
8条答案
按热度按时间ltqd579y1#
Dependency Injection
如果您注入Bar示例,或用于创建Bar示例的工厂(或其他483种方法之一),您将拥有执行测试所需的访问权限。
工厂示例:
给定一个这样写的Foo类:
字符串
在你的测试方法中,你可以像这样注入一个BarFactory:
型
奖励:这是一个TDD(测试驱动开发)如何驱动代码设计的例子。
eni9jsuy2#
经典的回答是“您不需要”。您测试的是
Foo
的公共API,而不是其内部。Foo
对象(或者环境中的其他对象)的行为是否受到foo()
的影响?如果是,测试它。如果不是,该方法做什么?js81xvg63#
我认为Mockito
@InjectMocks
是一条正确的路。根据您的意图,您可以使用:用途:
1.构造函数注入
1.属性设置器注入
1.现场注入
更多信息docs
下面是一个现场注入的例子:
类别:
字符串
试验项目:
型
eeq64g8w4#
如果你不想使用DI或工厂,你可以用一种巧妙的方式重构你的类:
字符串
你的测试类:
型
然后调用你的foo方法的类会这样做:
型
正如你所看到的,当以这种方式调用方法时,你不需要在调用你的foo方法的任何其他类中导入Bar类,这可能是你想要的。
当然,缺点是允许调用者设置Bar对象。
希望对你有帮助。
dgiusagp5#
使用
PowerMockito.whenNew
的示例代码的解决方案FooTest.java
字符串
JUnit输出x1c 0d1x
cig3rfwq6#
是的,如果你真的想/需要这样做,你可以使用PowerMock。这应该被认为是最后的手段。使用PowerMock,你可以使它从对构造函数的调用中返回一个mock。然后对mock进行验证。也就是说,csturtz的是“正确”的答案。
这里是Mock construction of new objects的链接
puruo6ea7#
我今天遇到了这个问题,我不想使用PowerMock或其他东西。我只是想做一个测试,以确保某个方法被调用。我找到了这篇文章,我看到没有人提到这种方法。
实现这一点的一种方法是不添加更多的依赖项或类似的技术,但它是有效的:
字符串
这很简单,很容易看出发生了什么。当我想要的方法被调用时(这里是模仿的),做这些事情。这些事情中有一个对AtomicallyIncrementAndGet的调用。你可以在这里使用int[],但在我看来这不是很清楚。我们只是使用了final的东西,我们可以递增。这是我们使用的lambda的限制。
这有点粗糙,但它可以简单直接地完成工作。至少如果你知道你的Brachdas和Mockito。
x7yiwoj48#
另一种简单的方法是在bar.someMethod()中添加一些log语句,然后确定在执行测试时可以看到所述消息,请参见此处的示例:How to do a JUnit assert on a message in a logger
当您的Bar.someMethod()是
private
时,这特别方便。