如何模拟字符串中使用mockito?
-
21-08-2019 - |
题
我需要一个模拟测试方案在这我打电话 getBytes()
方法的一串对象的,我得到一个UnsupportedEncodingException.
我试图来实现,采用下列代码:
String nonEncodedString = mock(String.class);
when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));
问题是,当我跑我的测试的情况下,我得到一个MockitoException说,我不能嘲笑一个java。郎。串类。
是否有办法的模拟字符串对象使用mockito,或者,一种方法,使我String对象引发UnsupportedEncodingException当我叫getBytes方法?
这里有更多的细节来说明问题:
这是班,我想试验:
public final class A {
public static String f(String str){
try {
return new String(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// This is the catch block that I want to exercise.
...
}
}
}
这是我的测试类(我采用JUnit4和mockito):
public class TestA {
@Test(expected=UnsupportedEncodingException.class)
public void test(){
String aString = mock(String.class);
when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));
A.f(aString);
}
}
解决方案
问题是Java中的String
类标记为final,所以你不能用传统的嘲弄框架嘲笑。按照常见问题的Mockito ,这是该框架的限制,以及。
其他提示
如何只用一个糟糕的编码名称创建一个String
?参见
public String(byte bytes[], int offset, int length, String charsetName)
惩戒String
几乎可以肯定是一个好主意。
如果你要在你的catch块做的是抛出一个运行时异常,那么你可以只使用一个字符集对象到指定的字符集的名称保存自己一些打字。
public final class A{
public static String f(String str){
return new String(str.getBytes(Charset.forName("UTF-8")));
}
}
这样,你不捕获异常,因为编译器会告诉你,绝不会只是碰巧。
正如其他人所指出的,则不能使用到的Mockito嘲笑final类。然而,更重要的一点是,测试是不是特别有用,因为它只是表明String.getBytes()
可以抛出一个异常,它可以明显做。如果你感到强烈的测试这个功能,我想你可以添加参数的编码f()
并发送一个错误值到测试。
此外,你是因为A.f()
是最终的,A
是静态导致对于f()
的呼叫者相同的问题。
本文章可能说服你的同事是约100%的代码覆盖率少教条是有用的:的如何失败,100%的测试覆盖率。
从它的文档,JDave不能删除从由引导类装载器装载的类的“最终”改性剂。这包括所有JRE类(从java.lang中,java.util中,等等)。
这是做一个工具,让你嘲笑什么是 JMockit 。
使用JMockit,测试可写为:
import java.io.*;
import org.junit.*;
import mockit.*;
public final class ATest
{
@Test(expected = UnsupportedOperationException.class)
public void test() throws Exception
{
new Expectations()
{
@Mocked("getBytes")
String aString;
{
aString.getBytes(anyString);
result = new UnsupportedEncodingException("Parsing error.");
}
};
A.f("test");
}
}
假设完全的 “A” 级是:
import java.io.*;
public final class A
{
public static String f(String str)
{
try {
return new String(str.getBytes("UTF-8"));
}
catch (UnsupportedEncodingException e) {
throw new UnsupportedOperationException(e);
}
}
}
我实际执行该测试在我的机器。 (请注意,我包裹在运行时异常原检查异常。)
我用部分嘲讽通过@Mocked("getBytes")
防止JMockit从嘲笑在java.lang.String
课堂上的一切(试想,可能会导致)。
现在,这个测试确实是不必要的,因为“UTF-8”是一个标准字符集,所需的在所有的JRE得到支持。因此,在生产环境中捕捉块将永远不会被执行。
“需要”或期望以覆盖catch块仍然有效,虽然。那么,如何摆脱测试不降低覆盖率?这里是我的想法:插入带有assert false;
作为catch块中的第一个语句行,并有报告覆盖措施时,代码覆盖工具忽略整个catch块。这是我的“TODO项目”为JMockit覆盖之一。 8 ^)
的Mockito不能嘲笑最终的类。 JMock的,从JDave CAN库相结合。 下面是说明。
JMock的没有做什么特别的不是依赖于JDave库在JVM来解除封口的一切,所以你可以使用JDave的unfinalizer实验,看看会的Mockito然后嘲笑它的其他final类。
您还可以使用PowerMock的扩展的Mockito嘲笑即使在系统类最终类/方法如String。不过,我想也对在此情况下,嘲讽的getBytes和相当尝试设置你的期望做到了真正的字符串填充与预期的数据来代替的建议。
你将被测试的代码,不可能执行。UTF-8的支持,需要在每一个Java VM,请参阅 http://java.sun.com/javase/6/docs/api/java/nio/charset/Charset.html
这是一个项目的要求,即所述单元测试覆盖百分比必须但比给定的值高。实现覆盖的该百分率测试必须覆盖相对于所述UnsupportedEncodingException catch块。
什么是定的覆盖目标是什么?有些人会说, 100%的覆盖率拍摄并不总是好主意。
此外,这是没有办法来测试catch块是否被行使。正确的方法是编写导致抛出异常的方法,使异常的观测抛出的成功标准。您可以通过将“预期”值与JUnit的@Test注解做到这一点:
@Test(expected=IndexOutOfBoundsException.class) public void outOfBounds() {
new ArrayList<Object>().get(1);
}
你尝试传递一个无效的charsetName到的getBytes(字符串)?
您可以实现一个辅助方法来获得的charsetName,并测试无义值内重写方法。
也许A.f(字符串)应该是A.f(CharSequence的)来代替。你可以模拟一个的CharSequence。
如果您可以使用JMockit,看罗杰里奥的答案。
当且仅当你的目标是让代码覆盖率但实际上没有模拟缺失的UTF-8将是什么样子,在运行时,你可以做以下的(而且你不能或不想使用JMockit):
public static String f(String str){
return f(str, "UTF-8");
}
// package private for example
static String f(String str, String charsetName){
try {
return new String(str.getBytes(charsetName));
} catch (UnsupportedEncodingException e) {
throw new IllegalArgumentException("Unsupported encoding: " + charsetName, e);
}
}
public class TestA {
@Test(expected=IllegalArgumentException.class)
public void testInvalid(){
A.f(str, "This is not the encoding you are looking for!");
}
@Test
public void testNormal(){
// TODO do the normal tests with the method taking only 1 parameter
}
}
您可以改变你的方法取接口CharSequence
:
public final class A {
public static String f(CharSequence str){
try {
return new String(str.getBytes("UTF-8"));
} catch (UnsupportedEncodingException e) {
// This is the catch block that I want to exercise.
...
}
}
}
这样的话,你还可以通过在字符串,但你可以嘲笑你喜欢的任何方式。
如果你有一个代码块,可从来没有真正运行和管理要求有100%的测试覆盖率,那么事情将不得不改变。
你可以做的是使字符编码成员变量,并添加一个包私有构造函数,类,可以让你通过它,在你的单元测试,你可以调用新的构造,与无义值的字符编码。