50

我有一节课。

Class First {

    private Second second;

    public First(int num, String str) {
        second = new Second(str);
        this.num = num;
    }

    ... // some other methods
}

我想为 First 类的公共方法编写单元测试。我想避免执行第二类的构造函数。

我这样做了:

Second second = Mockito.mock(Second.class);
Mockito.when(new Second(any(String.class))).thenReturn(null);
First first = new First(null, null);

它仍在调用第二类的构造函数。我怎样才能避免它?

4

7 回答 7

72

您可以使用PowerMockito

请参阅示例:

Second second = Mockito.mock(Second.class);
whenNew(Second.class).withNoArguments().thenReturn(second);

但重构是更好的决定。

于 2012-06-26T19:55:12.060 回答
32

单元测试的问题再次来自于使用new操作符手动创建对象。考虑传递已经创建的Second

class First {

  private Second second;

  public First(int num, Second second) {
    this.second = second;
    this.num = num;
  }

  // some other methods...
}

我知道这可能意味着对您的 API 进行重大重写,但没有其他方法。这个类也没有任何意义:

Mockito.when(new Second(any(String.class).thenReturn(null)));

首先,Mockito 只能模拟方法,不能模拟构造函数。其次,即使您可以模拟构造函数,您也是在模拟刚刚创建的对象的构造函数,而从未真正对该对象做任何事情。

于 2012-06-26T18:58:20.410 回答
17

这是使用 PowerMockito API 模拟此功能的代码。

Second mockedSecond = PowerMockito.mock(Second.class);
PowerMockito.whenNew(Second.class).withNoArguments().thenReturn(mockedSecond);

您需要使用 Powermockito 运行器,并且需要添加需要由 powermock API 模拟的所需测试类(逗号分隔)。

@RunWith(PowerMockRunner.class)
@PrepareForTest({First.class,Second.class})
class TestClassName{
    // your testing code
}
于 2015-11-20T09:18:27.270 回答
5

我使用了“模式 2 - “工厂助手模式”

模式 2 - 工厂助手模式

这种模式不起作用的一种情况是 MyClass 是最终的。大多数 Mockito 框架在 final 类中表现不佳;这包括使用 spy()。另一种情况是 MyClass 在某处使用 getClass(),并要求结果值为 MyClass。这是行不通的,因为 spy 的类实际上是原始类的 Mockito 生成的子类。

在这两种情况下,您都需要更健壮的工厂助手模式,如下所示。

public class MyClass{
  static class FactoryHelper{
      Foo makeFoo( A a, B b, C c ){
          return new Foo( a, b, c );
      }
  }

  //...

  private FactoryHelper helper;
  public MyClass( X x, Y y ){
      this( x, y, new FactoryHelper());
  } 

  MyClass( X x, Y, y, FactoryHelper helper ){

      //...

      this.helper = helper;
  } 

  //...

  Foo foo = helper.makeFoo( a, b, c );
}

因此,您有一个特殊的构造函数,仅用于测试,它有一个附加参数。这在您的测试类中使用,在创建您要测试的对象时。在您的测试类中,您模拟 FactoryHelper 类以及您要创建的对象。

@Mock private MyClass.FactoryHelper mockFactoryHelper;
@Mock private Foo mockFoo;
private MyClass toTest;

你可以像这样使用它

toTest = new MyClass( x, y, mockFactoryHelper ); 
when( mockFactoryHelper.makeFoo( 
  any( A.class ), any( B.class ), any( C.class )))
  .thenReturn( mockFoo ); 

来源:http ://web.archive.org/web/20160322155004/http://code.google.com/p/mockito/wiki/MockingObjectCreation

于 2014-01-21T15:56:09.750 回答
4

Mockito 现在可以模拟构造函数(从 3.5.0 版开始)https://javadoc.io/static/org.mockito/mockito-core/3.5.13/org/mockito/Mockito.html#mocked_construction

try (MockedConstruction mocked = mockConstruction(Foo.class)) {
   Foo foo = new Foo();
   when(foo.method()).thenReturn("bar");
   assertEquals("bar", foo.method());
   verify(foo).method();
 }
于 2020-09-30T14:51:08.590 回答
1

我相信,不可能使用 mockito 来模拟构造函数。相反,我建议采用以下方法

Class First {

   private Second second;

   public First(int num, String str) {
     if(second== null)
     {
       //when junit runs, you get the mocked object(not null), hence don't 
       //initialize            
       second = new Second(str);
     }
     this.num = num;
   }

   ... // some other methods
}

并且,对于测试:

class TestFirst{
    @InjectMock
    First first;//inject mock the real testable class
    @Mock
    Second second

    testMethod(){

        //now you can play around with any method of the Second class using its 
        //mocked object(second),like:
        when(second.getSomething(String.class)).thenReturn(null);
    }
}
于 2018-03-06T16:21:48.453 回答
-1

将此行包含在测试类的顶部

@PrepareForTest({ First.class })
于 2020-03-23T23:52:16.133 回答