在参数上调用方法时 PowerMockito 模拟静态方法失败
PowerMockito mocking static method fails when calling method on parameter
我正在尝试测试 class,它使用计算器 class 和许多静态方法。我已经以类似的方式成功地嘲笑了另一个 class,但事实证明这个更顽固。
似乎如果模拟方法包含对传入参数之一的方法调用,则静态方法不会被模拟(并且测试中断)。删除内部调用显然不是一个选项。我在这里明显遗漏了什么吗?
这是一个精简版,其行为方式相同...
public class SmallCalculator {
public static int getLength(String string){
int length = 0;
//length = string.length(); // Uncomment this line and the mocking no longer works...
return length;
}
}
这是测试...
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(""));
}
}
这个问题似乎有些混乱,所以我设计了一个更 'realistic' 的例子。这增加了一个间接级别,因此看起来我正在直接测试模拟方法。 SmallCalculator class 不变:
public class BigCalculator {
public int getLength(){
int length = SmallCalculator.getLength("random string");
// ... other logic
return length;
}
public static void main(String... args){
new BigCalculator();
}
}
这是新测试 class...
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());
}
}
使用 anyString()
而不是 any(String.class)
。
当使用 any(String.class)
时,传递的参数是 null
,因为 Mockito 将 return 引用类型的默认值,即 null
。结果你得到一个例外。
当使用anyString()
时,传递的参数将为空字符串。
注意,这解释了为什么会出现异常,但是您需要检查测试方法的方式,如其他评论和答案中所述。
首先,删除那一行:
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
因为你测试的是同样的方法。您不想模拟您正在测试的方法。
其次,将注释修改为:
@PrepareForTest({ SmallCalculator.class, String.class})
最后,为 length() 添加模拟;像这样:
given(String.length()).willReturn(5);
我觉得可以 ;)
我在这里找到了答案https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-java/
这是有效的最终代码。我已经在原始代码(以及人为的示例)中测试了这种方法,并且效果很好。简单...
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());
}
}
如果您不想调用实际的方法。而不是
when(myMethodcall()).thenReturn(myResult);
使用
doReturn(myResult).when(myMethodCall());
这是嘲讽的魔法,很难解释为什么它真的有效。
你忘记的另一件事是 mockStatic(SmallCalculator.class)
而且你不需要PowerMockito.spy(SmallCalculator.class);
我正在尝试测试 class,它使用计算器 class 和许多静态方法。我已经以类似的方式成功地嘲笑了另一个 class,但事实证明这个更顽固。
似乎如果模拟方法包含对传入参数之一的方法调用,则静态方法不会被模拟(并且测试中断)。删除内部调用显然不是一个选项。我在这里明显遗漏了什么吗?
这是一个精简版,其行为方式相同...
public class SmallCalculator {
public static int getLength(String string){
int length = 0;
//length = string.length(); // Uncomment this line and the mocking no longer works...
return length;
}
}
这是测试...
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(""));
}
}
这个问题似乎有些混乱,所以我设计了一个更 'realistic' 的例子。这增加了一个间接级别,因此看起来我正在直接测试模拟方法。 SmallCalculator class 不变:
public class BigCalculator {
public int getLength(){
int length = SmallCalculator.getLength("random string");
// ... other logic
return length;
}
public static void main(String... args){
new BigCalculator();
}
}
这是新测试 class...
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());
}
}
使用 anyString()
而不是 any(String.class)
。
当使用 any(String.class)
时,传递的参数是 null
,因为 Mockito 将 return 引用类型的默认值,即 null
。结果你得到一个例外。
当使用anyString()
时,传递的参数将为空字符串。
注意,这解释了为什么会出现异常,但是您需要检查测试方法的方式,如其他评论和答案中所述。
首先,删除那一行:
given(SmallCalculator.getLength(any(String.class))).willReturn(5);
因为你测试的是同样的方法。您不想模拟您正在测试的方法。
其次,将注释修改为:
@PrepareForTest({ SmallCalculator.class, String.class})
最后,为 length() 添加模拟;像这样:
given(String.length()).willReturn(5);
我觉得可以 ;)
我在这里找到了答案https://blog.codecentric.de/en/2011/11/testing-and-mocking-of-static-methods-in-java/
这是有效的最终代码。我已经在原始代码(以及人为的示例)中测试了这种方法,并且效果很好。简单...
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());
}
}
如果您不想调用实际的方法。而不是
when(myMethodcall()).thenReturn(myResult);
使用
doReturn(myResult).when(myMethodCall());
这是嘲讽的魔法,很难解释为什么它真的有效。
你忘记的另一件事是 mockStatic(SmallCalculator.class)
而且你不需要PowerMockito.spy(SmallCalculator.class);