java Mockito:如何验证方法是否在方法中创建的对象上调用?

kyks70gy  于 2024-01-05  发布在  Java
关注(0)|答案(8)|浏览(177)

我是新来的。
给定下面的类,我如何使用Mockito来验证someMethodfoo被调用后被调用了一次?

  1. public class Foo
  2. {
  3. public void foo(){
  4. Bar bar = new Bar();
  5. bar.someMethod();
  6. }
  7. }

字符串
我想打个电话确认一下,

  1. verify(bar, times(1)).someMethod();


其中barBar的模拟示例。

ltqd579y

ltqd579y1#

Dependency Injection
如果您注入Bar示例,或用于创建Bar示例的工厂(或其他483种方法之一),您将拥有执行测试所需的访问权限。
工厂示例:
给定一个这样写的Foo类:

  1. public class Foo {
  2. private BarFactory barFactory;
  3. public Foo(BarFactory factory) {
  4. this.barFactory = factory;
  5. }
  6. public void foo() {
  7. Bar bar = this.barFactory.createBar();
  8. bar.someMethod();
  9. }
  10. }

字符串
在你的测试方法中,你可以像这样注入一个BarFactory:

  1. @Test
  2. public void testDoFoo() {
  3. Bar bar = mock(Bar.class);
  4. BarFactory myFactory = new BarFactory() {
  5. public Bar createBar() { return bar;}
  6. };
  7. Foo foo = new Foo(myFactory);
  8. foo.foo();
  9. verify(bar, times(1)).someMethod();
  10. }


奖励:这是一个TDD(测试驱动开发)如何驱动代码设计的例子。

展开查看全部
eni9jsuy

eni9jsuy2#

经典的回答是“您不需要”。您测试的是Foo的公共API,而不是其内部。
Foo对象(或者环境中的其他对象)的行为是否受到foo()的影响?如果是,测试它。如果不是,该方法做什么?

js81xvg6

js81xvg63#

我认为Mockito @InjectMocks是一条正确的路。
根据您的意图,您可以使用:用途:
1.构造函数注入
1.属性设置器注入
1.现场注入
更多信息docs
下面是一个现场注入的例子:
类别:

  1. public class Foo
  2. {
  3. private Bar bar = new Bar();
  4. public void foo()
  5. {
  6. bar.someMethod();
  7. }
  8. }
  9. public class Bar
  10. {
  11. public void someMethod()
  12. {
  13. //something
  14. }
  15. }

字符串
试验项目:

  1. @RunWith(MockitoJUnitRunner.class)
  2. public class FooTest
  3. {
  4. @Mock
  5. Bar bar;
  6. @InjectMocks
  7. Foo foo;
  8. @Test
  9. public void FooTest()
  10. {
  11. doNothing().when( bar ).someMethod();
  12. foo.foo();
  13. verify(bar, times(1)).someMethod();
  14. }
  15. }

展开查看全部
eeq64g8w

eeq64g8w4#

如果你不想使用DI或工厂,你可以用一种巧妙的方式重构你的类:

  1. public class Foo {
  2. private Bar bar;
  3. public void foo(Bar bar){
  4. this.bar = (bar != null) ? bar : new Bar();
  5. bar.someMethod();
  6. this.bar = null; // for simulating local scope
  7. }
  8. }

字符串
你的测试类:

  1. @RunWith(MockitoJUnitRunner.class)
  2. public class FooTest {
  3. @Mock Bar barMock;
  4. Foo foo;
  5. @Test
  6. public void testFoo() {
  7. foo = new Foo();
  8. foo.foo(barMock);
  9. verify(barMock, times(1)).someMethod();
  10. }
  11. }


然后调用你的foo方法的类会这样做:

  1. public class thirdClass {
  2. public void someOtherMethod() {
  3. Foo myFoo = new Foo();
  4. myFoo.foo(null);
  5. }
  6. }


正如你所看到的,当以这种方式调用方法时,你不需要在调用你的foo方法的任何其他类中导入Bar类,这可能是你想要的。
当然,缺点是允许调用者设置Bar对象。
希望对你有帮助。

展开查看全部
dgiusagp

dgiusagp5#

使用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
    FooTest.java
  1. package foo;
  2. import org.junit.After;
  3. import org.junit.Before;
  4. import org.junit.Test;
  5. import org.junit.runner.RunWith;
  6. import org.mockito.Mock;
  7. import org.mockito.Mockito;
  8. import org.powermock.api.mockito.PowerMockito;
  9. import org.powermock.core.classloader.annotations.PrepareForTest;
  10. import org.powermock.modules.junit4.PowerMockRunner;
  11. //Both @PrepareForTest and @RunWith are needed for `whenNew` to work
  12. @RunWith(PowerMockRunner.class)
  13. @PrepareForTest({ Foo.class })
  14. public class FooTest {
  15. // Class Under Test
  16. Foo cut;
  17. @Mock
  18. Bar barMock;
  19. @Before
  20. public void setUp() throws Exception {
  21. cut = new Foo();
  22. }
  23. @After
  24. public void tearDown() {
  25. cut = null;
  26. }
  27. @Test
  28. public void testFoo() throws Exception {
  29. // Setup
  30. PowerMockito.whenNew(Bar.class).withNoArguments()
  31. .thenReturn(this.barMock);
  32. // Test
  33. cut.foo();
  34. // Validations
  35. Mockito.verify(this.barMock, Mockito.times(1)).someMethod();
  36. }
  37. }

字符串

JUnit输出x1c 0d1x

展开查看全部
cig3rfwq

cig3rfwq6#

是的,如果你真的想/需要这样做,你可以使用PowerMock。这应该被认为是最后的手段。使用PowerMock,你可以使它从对构造函数的调用中返回一个mock。然后对mock进行验证。也就是说,csturtz的是“正确”的答案。
这里是Mock construction of new objects的链接

puruo6ea

puruo6ea7#

我今天遇到了这个问题,我不想使用PowerMock或其他东西。我只是想做一个测试,以确保某个方法被调用。我找到了这篇文章,我看到没有人提到这种方法。
实现这一点的一种方法是不添加更多的依赖项或类似的技术,但它是有效的:

  1. @Test
  2. public void testSomeMethodIsCalledOnce() throws Exception {
  3. final AtomicInteger counter = new AtomicInteger(0);
  4. Mockito.when(someObject.theMethodIWant(anyString()))
  5. .then((Answer<ReturnValue>) __ -> {
  6. counter.incrementAndGet();
  7. return theExpectedAnswer;
  8. });
  9. theObjectUnderTest.theMethod(someTestValue);
  10. assertEquals(1, counter.get());
  11. }

字符串
这很简单,很容易看出发生了什么。当我想要的方法被调用时(这里是模仿的),做这些事情。这些事情中有一个对AtomicallyIncrementAndGet的调用。你可以在这里使用int[],但在我看来这不是很清楚。我们只是使用了final的东西,我们可以递增。这是我们使用的lambda的限制。
这有点粗糙,但它可以简单直接地完成工作。至少如果你知道你的Brachdas和Mockito。

展开查看全部
x7yiwoj4

x7yiwoj48#

另一种简单的方法是在bar.someMethod()中添加一些log语句,然后确定在执行测试时可以看到所述消息,请参见此处的示例:How to do a JUnit assert on a message in a logger
当您的Bar.someMethod()是private时,这特别方便。

相关问题