调用参数上的方法时,PowerMockito模拟静态方法失败

时间:2015-07-23 12:43:59

标签: java unit-testing powermockito

我试图测试一个使用带有许多静态方法的计算器类的类。我以类似的方式成功地嘲笑了另一个班级,但这个问题更加顽固。

似乎如果mocked方法在传入的参数之一上包含方法调用,则静态方法不会被模拟(并且测试中断)。删除内部呼叫显然不是一种选择。我有什么明显的遗失吗?

这是一个精简版,其行为方式相同...

import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;

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

import com.solveit.aps.transport.model.impl.SmallCalculator;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SmallCalculator.class})
public class SmallTester {

    @Test
    public void smallTest(){

        PowerMockito.spy(SmallCalculator.class);
        given(SmallCalculator.getLength(any(String.class))).willReturn(5);

        assertEquals(5, SmallCalculator.getLength(""));
    }
}

这是考验......

public class BigCalculator {

    public int getLength(){

        int length  = SmallCalculator.getLength("random string");

        // ... other logic

        return length;
    }

    public static void main(String... args){

        new BigCalculator();
    }
}

似乎对这个问题存在一些困惑,所以我设计了一个更现实的问题。例。这个增加了一个间接级别,因此我没有看到我直接测试模拟方法。 SmallCalculator类保持不变:

import static org.junit.Assert.assertEquals;
import static org.mockito.BDDMockito.given;
import static org.mockito.Matchers.any;

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

import com.solveit.aps.transport.model.impl.BigCalculator;
import com.solveit.aps.transport.model.impl.SmallCalculator;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SmallCalculator.class})
public class BigTester {

    @Test
    public void bigTest(){

        PowerMockito.spy(SmallCalculator.class);
        given(SmallCalculator.getLength(any(String.class))).willReturn(5);

        BigCalculator bigCalculator = new BigCalculator();
        assertEquals(5, bigCalculator.getLength());
    }
}

这是新的测试类...

remote:true

4 个答案:

答案 0 :(得分:16)

我在https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-java/

找到了答案

这是最终的代码。我已经在原始代码(以及人为的例子)中测试了这种方法,并且效果很好。 Simples ...

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.any;

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

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SmallCalculator.class})
public class BigTester {

    @Test
    public void bigTest(){

        PowerMockito.mockStatic(SmallCalculator.class);
        PowerMockito.when(SmallCalculator.getLength(any(String.class))).thenReturn(5);

        BigCalculator bigCalculator = new BigCalculator();
        assertEquals(5, bigCalculator.getLength());
    }
}

答案 1 :(得分:1)

使用anyString()代替any(String.class)

使用any(String.class)时,传递的参数为null,因为Mockito将返回引用类型的默认值,即null。结果你得到了一个例外。

使用anyString()时,传递的参数将为空字符串。

请注意,这解释了为什么会出现异常,但是您需要检查测试方法的方式,如其他评论和答案中所述。

答案 2 :(得分:1)

首先,删除该行:

given(SmallCalculator.getLength(any(String.class))).willReturn(5);

因为您正在测试相同的方法。你不想嘲笑你正在测试的方法。

其次,将注释修改为:

@PrepareForTest({ SmallCalculator.class, String.class})

最后,为length()添加模拟;像这样:

given(String.length()).willReturn(5);

我认为它会做;)

答案 3 :(得分:0)

如果您不希望调用实际方法。而不是

when(myMethodcall()).thenReturn(myResult);

使用

doReturn(myResult).when(myMethodCall());

这是嘲弄魔法,很难解释为什么它真的有效。

你遗忘的其他事情是mockStatic(SmallCalculator.class)

您不需要PowerMockito.spy(SmallCalculator.class);