如何在动态加载的jar中模拟方法

时间:2016-09-16 16:37:34

标签: java class reflection mockito

我有一个叫做Price with constructor的类,我通过反射动态加载它:

public Price(Context context, String pair) {
    this.context = context;
    this.value1 = pair.substring(0, 3);
    this.value2 = pair.substring(3, 6);
    this.dps = context.getService().getm1(value1, value2).getm2();
}

但是我想模拟Context对象

我想要

context.getService().getm1(value1, value2).getm2()

返回5.

这是我试过的

//mocking the Context class
Class<?> contextClass = urlClassLoader.loadClass("com.algo.Context");
constructor =contextClass.getConstructor();
Object context = Mockito.mock(contextClass);

//trying to instantiate the Price class
Class<?> priceClass = urlClassLoader.loadClass("com.algo.Price");
constructor = priceClass.getConstructor(contextClass,String.class);
Mockito.when(context.getService().getm1(value1, value2).getm2().thenReturn(5));
Object price = constructor.newInstance(context,"PRICES");

但我在

下面有一条红线
context.getService()

错误说

The method getService() is undefined for the type Object

我如何解决这个问题,我的最终目标是使用变量

创建Price对象
dps

是一个int 5,这就是我想模拟Context对象的原因。

2 个答案:

答案 0 :(得分:1)

对我而言,唯一的方法是使用反射来实现整个测试,这在你的情况下非常费力,因为你需要为每个方法调用做同样的事情,因为你不能直接模拟context.getService().getm1(value1, value2).getm2()

假设我的课程Context如下

public class Context {

    public int getm1(String value1, String value2) {
        return -1;
    }
}

正常的测试用例是:

@Test
public void normal() throws Exception {
    Context context = Mockito.mock(Context.class);
    Mockito.when(context.getm1(Mockito.anyString(), Mockito.anyString())).thenReturn(5);
    Assert.assertEquals(5, context.getm1("foo", "bar"));
}

使用反射的相同测试将是:

@Test
public void reflection() throws Exception {
    ... // Here I get the classloader
    // Get the class by reflection
    Class<?> contextClass = urlClassLoader.loadClass("com.algo.Context");
    // Mock the class
    Object context = Mockito.mock(contextClass);
    // Get the method by reflection
    Method method = contextClass.getMethod("getm1", String.class, String.class);
    // Invoke the method with Mockito.anyString() as parameter 
    // to get the corresponding methodCall object
    Object methodCall = method.invoke(context, Mockito.anyString(), Mockito.anyString());
    // Mock the method call to get what we expect
    Mockito.when(methodCall).thenReturn(5);
    // Test the method with some random values by reflection
    Assert.assertEquals(5, method.invoke(context, "foo", "bar"));
}

答案 1 :(得分:0)

无法真正理解这个问题。如果您使用的是未知类型,则无法在construtor中键入Context。

但独立地,一种方法是创建表示上下文的预期结构的接口,然后模拟接口以返回值。 如果以任何方式模拟它,就没有必要在测试中真正加载动态类。