代码之家  ›  专栏  ›  技术社区  ›  Matteo NNZ

在调用公共的非静态方法时,是否可以模拟实用程序对象的响应?[副本]

  •  0
  • Matteo NNZ  · 技术社区  · 7 年前

    我只有一节课。

    Class First {
    
        private Second second;
    
        public First(int num, String str) {
            second = new Second(str);
            this.num = num;
        }
    
        ... // some other methods
    }
    

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

    我做到了:

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

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

    0 回复  |  直到 8 年前
        1
  •  25
  •   satanas serge_gubenko    12 年前

    单元测试的问题再次来自于使用 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
  •  61
  •   try-catch-finally zloctb    9 年前

    你可以用 PowerMockito

    See the example:

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

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

        3
  •  14
  •   Rocky Mena    8 年前

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

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

    您需要使用Powermockito runner并添加所需的测试类( 逗号分隔 )它们需要由powermock API模拟。

    @RunWith(PowerMockRunner.class)
    @PrepareForTest({First.class,Second.class})
    class TestClassName{
        // your testing code
    }
    
        4
  •  4
  •   try-catch-finally zloctb    9 年前

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

    模式2-工厂助手模式

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

    在这两种情况下,您都需要稍微健壮一点的factory helper模式,如下所示。

    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

        5
  •  0
  •   Rishabh Sachdeva    8 年前

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

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