如何模拟使用反射(即newinstance()方法创建的对象构造



我在下面有一个代码,其中员工班级使用反射创建AppraisalCalculator的对象。我想使用PowerMockito模拟此AppraisalCalculator对象。

class AppraisalCalculator {
    public int appraisal() {
        return 300;
    }
}
class Employee {
    public int updateSalary() {
        // line 1
        AppraisalCalculator ac = 
            AppraisalCalculator.class.getConstructor().newInstance();
        return ac.appraisal();
    }
}
class TestRunner {
    @Test
    public void test() {
        AppraisalCalulator acMock=PowerMockito.mock(AppraisalCalculator.class);   
        PowerMockito
            .whenNew(AppraisalCalculator.class)
            .withNoArguments()
            .thenReturn(600);
        Employee emp = new Employee();
        int actualValue = emp.updateSalary();
        int expectedValue=600;
        Assert.equals(expectedValue,actualValue);
    }
}

在这里,即使我嘲笑了评估计算器对象,它仍然调用AppraisalCalculator的真实appraisal()方法。如果使用新操作员而不是newInstance()创建了第1行的实际AppraisalCalculator,则此模拟有效。

有人可以解释为什么使用反射创建实际对象,为什么这不起作用?在这种情况下,我该怎么做才能模拟此对象?

让我首先首先重新提出问题将完全工作代码。

@RunWith(PowerMockRunner.class)
@PrepareForTest(Employee.class)
public class TestRunner {
    @Test
    public void test() throws Exception {
        AppraisalCalculator acMock = PowerMockito.mock(AppraisalCalculator.class);
        PowerMockito
                .whenNew(AppraisalCalculator.class)
                .withNoArguments()
                .thenReturn(acMock);
        when(acMock.appraisal()).thenReturn(600);
        Employee emp = new Employee();
        int actualValue = emp.updateSalary();
        int expectedValue = 600;
        assertEquals(expectedValue, actualValue);
    }
}

然后,PowerMock的工作方式是PowerMockRunner将查看需要准备的每个类(在此处Employee(,然后查找对我们要替换并进行操作的构造函数的调用。这是在课堂加载下完成的。真实的类字节码调用构造函数由返回模拟的一个代替。

问题是,如果您正在使用反射,那么PowerMock就无法通过阅读该构造函数的字节码来知道。之后只会动态地知道它。所以没有嘲笑。

如果您确实需要创建以反射嘲笑的类,我实际上会重构代码。

Employee中,我会添加

之类的东西
protected AppraisalCalculator getCalculator() {
    try {
        return AppraisalCalculator.class.newInstance();
    } catch (InstantiationException | IllegalAccessException e) {
        throw new RuntimeException(e);
    }
}

是一种用于隔离计算器结构的方法。

,只需创建一个孩子班

    @Test
    public void testWithChildClass() {
        // Note that you don't need PowerMock anymore
        AppraisalCalculator acMock = Mockito.mock(AppraisalCalculator.class);
        when(acMock.appraisal()).thenReturn(600);
        Employee emp = new Employee() {
            @Override
            protected AppraisalCalculator getCalculator() {
                return acMock;
            }
        };
        int actualValue = emp.updateSalary();
        int expectedValue = 600;
        assertEquals(expectedValue, actualValue);
    }

或部分模拟(间谍(

    @Test
    public void test2() {
        // No PowerMock either here
        AppraisalCalculator acMock = Mockito.mock(AppraisalCalculator.class);
        when(acMock.appraisal()).thenReturn(600);
        Employee emp = spy(new Employee());
        doReturn(acMock).when(emp).getCalculator();
        int actualValue = emp.updateSalary();
        int expectedValue = 600;
        assertEquals(expectedValue, actualValue);
    }

相关内容

  • 没有找到相关文章

最新更新