其他 class 中带有参数的 doNothing void 方法

doNothing void method with params in other class

我目前有 2 个 类:

public class aClass{
   public void meth1(){
      bClass b = new bClass();
      b.meth2();// i dont want to call this method
      //buss logic
   }
}

public class bClass{
   public void meth2(){
      // some logic
   } 
}

目前我正在为 aClass 中的 meth1 创建一个 junit 测试用例。 但是,我不想调用bClass中的meth2,直接执行aClass中的busslogic

aClassbClass 是固定的 - 我不能(也不会)更改 aClassbClass 上的代码。

我尝试了很多事情,比如@injectmock 和 doNothing 使用 mokito 和 power mock,但是当我在 aClass 中调用 meth1 时总是调用 meth2

我该怎么做才能解决这个问题?

You can do this with Powermockito。 link 解释了所有细节。以下是您的示例的外观。

@RunWith(PowerMockRunner.class)
@PrepareForTest(aClass.class)
public class aClassTesting {

    @Mock
    bClass mockB;


    @Test
    public void testMeth1(){

        //prepare mocks
        whenNew(bClass.class).withNoArguments().thenReturn(mockB);
        doNothing().when(mockB).meth2();

        //run it
        aClass instance = new aClass();
        aClass.meth1();

        //asserts and verify
        verifyNew(bClass.class).withNoArguments();
        verify(mockB, times(1)).meth2();
    }

}

编辑:

当您使用 @Mock 模拟 bClass 实例时,它会用模拟方法替换该实例中的所有方法。如果您只想模拟 bCLass 中的某些方法,那么您必须监视 bCLass 实例而不是模拟它。 Spy 只模拟你想要的方法。因此,只需在我的示例中将 @Mock 替换为 @Spy ,那么只有 meth2 会被阻止,而 bClass 中的任何其他方法都不会被阻止。

就目前而言,由于无法更改 AClass 的限制,唯一的解决方案是使用 Powermock(或类似工具)。 Mockito 本身无法替换构造函数(被视为静态方法调用),因此您唯一的解决方案是重写 aClass。

对于任何未来发现这个问题但没有那个约束的读者,bClass 的快速重构将使它更容易测试。

public class aClass{    
   public void meth1(){
      meth1(new bClass());
   }

   /** Package private for testing. */
   public void meth1(bClass b){
      b.meth2();
      //buss logic
   }
}

此时,您可以传递一个mock bClass 并调用单参数重载来测试您的业务逻辑。您还可以将 b.meth2() 移出单参数方法并移入 public 无参数方法,如果它的行为更像设置调用。

您可以使用 mockito...

public class aClass {
    private final bClass b;

    public aClass() {
        this.b = new bClass()    
    }

    public aClass(bClass b) {
        this.b = b;
    }

    ....
}

@RunWith(MockitoJUnitRunner.class)        
public class aClassTest {

    @Mock
    private final bClass b;

    @InjectMocks
    private aClass a;

    ....

}