用mockito为构造函数进行单元测试

时间:2012-06-26 18:54:42

标签: java unit-testing mockito

我有一节课。

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);

它仍在调用类Second的构造函数。我怎么能避免它?

7 个答案:

答案 0 :(得分:60)

您可以使用PowerMockito

See the example:

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

但重新分解是更好的决定。

答案 1 :(得分:25)

单元测试的问题再次来自使用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只能模拟方法,而不是构造函数。其次,即使你可以模拟构造函数,你也在嘲笑刚刚创建的对象的构造函数,并且从不真正对该对象做任何事情。

答案 2 :(得分:13)

以下是使用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
}

答案 3 :(得分:4)

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

  

模式2 - 工厂帮助模式

     

这种模式不起作用的一种情况是MyClass是最终的。大多数Mockito框架在最终课程中表现不佳;这包括使用spy()。另一种情况是MyClass在某处使用getClass(),并且要求结果值为MyClass。这是行不通的,因为间谍的类实际上是原始类的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

答案 4 :(得分:1)

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();
 }

答案 5 :(得分:0)

我相信,使用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);
        }

答案 6 :(得分:0)

在测试类的顶部加上这一行

@PrepareForTest({ First.class })