从另一个类方法调用时无法正确模拟方法调用

时间:2022-10-29 16:05:07
MyClass firstClass = PowerMockito.spy(new MyClass());

AnotherClass secondClass;
secondClass = PowerMockito.mock(AnotherClass.class);
PowerMockito.when(secondClass.anotherFunction(Mockito.any()).thenReturn(1);

int myInt = firstClass.myFunction();

if (myInt == 1) {
    System.out.println("true");
}

myFunction calls anotherFunction and returns the results of anotherFunction.

myFunction调用anotherFunction并返回anotherFunction的结果。

But it's not returning 1 and printing "true" like I would expect, instead it's still doing its real functionality.

但它并没有像我期望的那样返回1并打印“真实”,而是仍然在做它真正的功能。

What am I missing here?

我在这里想念的是什么?

1 个解决方案

#1


2  

An instance of AnotherClass is created inside myFunction then the instance is used to call secondClass.anotherFunction from inside myFunction.

在myFunction中创建了AnotherClass的实例,然后该实例用于从myFunction内部调用secondClass.anotherFunction。

Right. That means that the real instance is used, not the mock. The method under test is tightly coupled to the dependency because it creates a real instance on its own

对。这意味着使用了真实实例,而不是模拟。测试中的方法与依赖项紧密耦合,因为它自己创建了一个真实的实例

public class MyClass {

    public int myFunction() {
        AnotherClass secondClass = new AnotherClass();

        int result = secondClass.anotherFunction(someValue);

        //...

        return result;
    }    
}

How can I use the mocked instance instead?

我怎样才能使用模拟实例?

You either refactor to have the second class injected, either via constructor or method parameter, which is a clean code design or you use powermock to mock the initialization of the second class, which in my opinion is poor design.

你要么重构注入第二个类,要么通过构造函数或方法参数,这是一个干净的代码设计,或者你使用powermock来模拟第二类的初始化,在我看来这是一个糟糕的设计。

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class) //<-- you must prepare the class creating the new instance
public class MyClassTest {
    @Test
    public void test() {
        //Arrange
        int expected = 1;                          
        //Mock second class
        AnotherClass secondClass;
        secondClass = PowerMockito.mock(AnotherClass.class);
        PowerMockito.when(secondClass.anotherFunction(Mockito.any()).thenReturn(expected);

        //mocking initialization of second class withing first class
        PowerMockito.whenNew(AnotherClass.class).withNoArguments().thenReturn(secondClass);

        MyClass firstClass = new MyClass();

        //Act
        int actual = firstClass.myFunction();

        //Assert                
        assertEquals(expected, actual);
    }
}

Reference How to mock construction of new objects

参考如何模拟新对象的构造

#1


2  

An instance of AnotherClass is created inside myFunction then the instance is used to call secondClass.anotherFunction from inside myFunction.

在myFunction中创建了AnotherClass的实例,然后该实例用于从myFunction内部调用secondClass.anotherFunction。

Right. That means that the real instance is used, not the mock. The method under test is tightly coupled to the dependency because it creates a real instance on its own

对。这意味着使用了真实实例,而不是模拟。测试中的方法与依赖项紧密耦合,因为它自己创建了一个真实的实例

public class MyClass {

    public int myFunction() {
        AnotherClass secondClass = new AnotherClass();

        int result = secondClass.anotherFunction(someValue);

        //...

        return result;
    }    
}

How can I use the mocked instance instead?

我怎样才能使用模拟实例?

You either refactor to have the second class injected, either via constructor or method parameter, which is a clean code design or you use powermock to mock the initialization of the second class, which in my opinion is poor design.

你要么重构注入第二个类,要么通过构造函数或方法参数,这是一个干净的代码设计,或者你使用powermock来模拟第二类的初始化,在我看来这是一个糟糕的设计。

@RunWith(PowerMockRunner.class)
@PrepareForTest(MyClass.class) //<-- you must prepare the class creating the new instance
public class MyClassTest {
    @Test
    public void test() {
        //Arrange
        int expected = 1;                          
        //Mock second class
        AnotherClass secondClass;
        secondClass = PowerMockito.mock(AnotherClass.class);
        PowerMockito.when(secondClass.anotherFunction(Mockito.any()).thenReturn(expected);

        //mocking initialization of second class withing first class
        PowerMockito.whenNew(AnotherClass.class).withNoArguments().thenReturn(secondClass);

        MyClass firstClass = new MyClass();

        //Act
        int actual = firstClass.myFunction();

        //Assert                
        assertEquals(expected, actual);
    }
}

Reference How to mock construction of new objects

参考如何模拟新对象的构造