Alc*_*sta 38 java unit-testing mocking mockito
我需要模拟一个测试场景,我在其中调用getBytes()String对象的方法,并得到UnsupportedEncodingException.
我试图使用以下代码实现:
String nonEncodedString = mock(String.class);
when(nonEncodedString.getBytes(anyString())).thenThrow(new UnsupportedEncodingException("Parsing error."));
Run Code Online (Sandbox Code Playgroud)
问题是,当我运行我的测试用例时,我得到一个MockitoException,表示我无法模拟java.lang.String类.
有没有办法使用mockito模拟String对象,或者,当我调用getBytes方法时,一种方法使我的String对象抛出UnsupportedEncodingException?
以下是更多细节来说明问题:
这是我要测试的类:
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.
...
}
}
}
Run Code Online (Sandbox Code Playgroud)
这是我的测试类(我使用的是JUnit 4和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);
}
}
Run Code Online (Sandbox Code Playgroud)
Pet*_*ter 39
问题是StringJava中的类被标记为final,因此您无法使用传统的模拟框架进行模拟.根据Mockito FAQ,这也是该框架的限制.
Ste*_*man 13
如何String使用错误的编码名称创建一个?看到
public String(byte bytes[], int offset, int length, String charsetName)
Run Code Online (Sandbox Code Playgroud)
模拟String几乎肯定是一个坏主意.
小智 13
如果您要在catch块中执行的操作是抛出运行时异常,那么只需使用Charset对象来指定您的字符集名称,就可以节省一些输入.
public final class A{
public static String f(String str){
return new String(str.getBytes(Charset.forName("UTF-8")));
}
}
Run Code Online (Sandbox Code Playgroud)
这样你就不会捕获一个永远不会因为编译器告诉你而发生的异常.
正如其他人所指出的那样,你不能用Mockito来模拟最后一堂课.但是,更重要的一点是测试不是特别有用,因为它只是证明String.getBytes()可以抛出异常,这显然可以做到.如果您对测试此功能感到强烈,我想您可以为编码添加参数f()并将错误值发送到测试中.
此外,您导致调用者的相同问题A.f()因为A是最终的并且f()是静态的.
本文可能有助于说服您的同事减少100%的代码覆盖率:如何以100%的测试覆盖率失败.
从其文档中,JDave无法从引导类加载器加载的类中删除"final"修饰符.这包括所有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");
}
}
Run Code Online (Sandbox Code Playgroud)
假设完整的"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);
}
}
}
Run Code Online (Sandbox Code Playgroud)
我实际上在我的机器上执行了这个测试.(注意,我在运行时异常中包装了原始的已检查异常.)
我使用了部分模拟@Mocked("getBytes")来阻止JMockit模拟java.lang.String类中的所有内容(想象一下这可能导致什么).
现在,这个测试确实是不必要的,因为"UTF-8"是一个标准的字符集,需要在所有JRE中得到支持.因此,在生产环境中,永远不会执行catch块.
但是,"需要"或希望覆盖捕获块仍然有效.那么,如何在不降低覆盖率的情况下摆脱测试呢?这是我的想法:assert false;在catch块中插入一行作为第一个语句,并在报告覆盖率度量时让代码覆盖率工具忽略整个catch块.这是JMockit Coverage的"TODO项目"之一.8 ^)
| 归档时间: |
|
| 查看次数: |
50930 次 |
| 最近记录: |