Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/402.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何模拟从类级对象调用的方法_Java_Unit Testing_Mockito_Powermockito - Fatal编程技术网

Java 如何模拟从类级对象调用的方法

Java 如何模拟从类级对象调用的方法,java,unit-testing,mockito,powermockito,Java,Unit Testing,Mockito,Powermockito,我正在为类a编写单元测试,我想模拟一个方法,但该方法是从类级对象调用的,我将如何模拟它 让我从例子中解释一下 正在测试的A类 public class ClassA { ClassB objectOfB = new ClassB(); public int add(int a, int b) { int addition = objectOfB.performCalculation(a,b); return addition; } }

我正在为类a编写单元测试,我想模拟一个方法,但该方法是从类级对象调用的,我将如何模拟它

让我从例子中解释一下

正在测试的A类

public class ClassA {
    ClassB objectOfB = new ClassB();
    public int add(int a, int b) {
        int addition = objectOfB.performCalculation(a,b);
        return addition;
    }
}

类,它具有一些业务逻辑

  public class ClassB {
    public int performCalculation(int a, int b) {
        int c = a+b;
        System.out.println("I am not mocked, I am actual call");
        System.out.println("Returning " + c + " From ClassB");
        return c;
    }
  }

笔试

import static org.junit.Assert.*;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.InjectMocks;
import org.mockito.Mockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class, ClassB.class})
public class ClassATest {
    @InjectMocks
    ClassA objA = new ClassA();

    @Test
    public void testAddFromClassA() throws Exception {
        ClassB objB = Mockito.mock(ClassB.class);
        Mockito.when(objB.performCalculation(5, 10)).thenReturn(15);
        int result = objA.add(5, 10);
        assertEquals(result, 15);
    }

}

测试结果:

这个测试是通过的,但它不是在模仿ClassB的方法,而是在执行实际的调用


要求:

在编写测试时,我想模拟行:objectOfB.performCalculation(a,b);从类A中,但正如您所看到的,classB()的对象是在类级别上创建的

我怎么能嘲笑这个

我应该在考试课上写些什么


模拟类的初始化,以便在执行测试时使用模拟

@RunWith(PowerMockRunner.class)
@PrepareForTest({ClassA.class}) //prepare the class creating the new instance of ClassB for test, not the ClassB itself.
public class ClassATest {
    @Test
    public void testAddFromClassA() throws Exception {
        int expected = 15;
        ClassB objB = Mockito.mock(ClassB.class);
        Mockito.when(objB.performCalculation(5, 10)).thenReturn(expected);

        //mocking initialization of ClassB class withing ClassA class
        PowerMockito.whenNew(ClassB.class).withNoArguments().thenReturn(objB);

        ClassA objA = new ClassA();

        //Act
        int actual = objA.add(5, 10);

        //Assert
        assertEquals(expected, actual);
    }
}
参考文献 话虽如此,理想情况下,目标类应该通过构造函数注入遵循显式依赖原则

public class ClassA {
    final ClassB objectOfB;

    public ClassA(ClassB objectOfB) {
        this.objectOfB = objectOfB;
    }

    public int add(int a, int b) {
        int addition = objectOfB.performCalculation(a,b);
        return addition;
    }
}
允许类显式声明它执行其设计功能所依赖的内容

它还允许控制反转和松耦合,这使得类的维护和测试更加灵活

@RunWith(PowerMockRunner.class)
public class ClassATest {
    @Test
    public void testAddFromClassA() throws Exception {
        int expected = 15;
        ClassB objB = Mockito.mock(ClassB.class);
        Mockito.when(objB.performCalculation(5, 10)).thenReturn(expected);

        ClassA objA = new ClassA(objB);

        //Act
        int actual = objA.add(5, 10);

        //Assert
        assertEquals(expected, actual);
    }
}
仅仅因为PowerMockito允许新对象的模拟构造,并不意味着我们应该这样做


如果遵循了正确的设计原则,那么就真的没有必要进行此类攻击。

我建议多读一点关于模拟的内容以及如何进行模拟。 查看您尝试运行的测试代码:

  ClassB objB = Mockito.mock(ClassB.class);
  Mockito.when(objB.performCalculation(5, 10)).thenReturn(15);
  int result = objA.add(5, 10);
  assertEquals(result, 15);
发生了什么事
您正在模拟ClassB,但未使用模拟实例
objB

当你模拟一个类时,你会得到一个模拟的实例,这并不意味着这个类现在通过你的测试被模拟了,它只是意味着你可以使用Mockito来操作这个特定的instace

该怎么办
如果您不能使用该实例来测试依赖于它的方法,就像在您的案例中一样,这意味着您在这两个类之间有很强的依赖性,如果这是测试的问题,则通常意味着您的设计是错误的。您应该能够将ClassA注入ClassB,或者在构造函数中为其提供参数

public ClassA(ClassB bInstance){
   this.bIntance = bInstance
}
或者,如果这使特定操作成为自变量,则作为函数参数

public add(ClassB classBInstance, int a, int b){
    classBInstance. performCalculation(a.b)
}
这将允许您模拟一个实例,并使用您模拟的特定植入运行ClassA函数:

ClassB classBInstance1 = Mockito.mock(ClassB.class)
ClassB classBInstance2 = Mockito.mock(ClassB.class)
Mockito.when(classBInstance1.performCalculation(5, 10)).thenReturn(15);
Mockito.when(classBInstance2.performCalculation(5, 10)).thenReturn(42); 
new ClassA(classBInstance1).add(5,10) //returns 15
new ClassA(classBInstance2).add(5,10) //returns 42
new ClassA().add(classBInstance1,5,10) //15
new ClassA().add(classBInstance2,5,10) //42