Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/string/5.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 验证组件是否可以保存/检索UTF8编码字符串的最低测试是什么_Java_String_Encoding_Utf 8 - Fatal编程技术网

Java 验证组件是否可以保存/检索UTF8编码字符串的最低测试是什么

Java 验证组件是否可以保存/检索UTF8编码字符串的最低测试是什么,java,string,encoding,utf-8,Java,String,Encoding,Utf 8,我正在集成测试一个组件。该组件允许您保存和获取字符串 我想验证组件是否正确处理UTF-8字符。验证这一点所需的最低测试是什么 我认为这样做是一个好的开始: // This is the ☺ character String toSave = "\u263A"; int id = 123; // Saves to Database myComponent.save( id, toSave ); // Retrieve from Database String fromComponent = m

我正在集成测试一个组件。该组件允许您保存和获取字符串

我想验证组件是否正确处理UTF-8字符。验证这一点所需的最低测试是什么

我认为这样做是一个好的开始:

// This is the ☺ character
String toSave = "\u263A";
int id = 123;

// Saves to Database
myComponent.save( id, toSave );

// Retrieve from Database
String fromComponent = myComponent.retrieve( id );

// Verify they are same 
org.junit.Assert.assertEquals( toSave, fromComponent );
我过去犯的一个错误是我将
字符串设置为save=“è”
。我的测试通过了,因为字符串已正确保存并从数据库中检索到。不幸的是,由于应用程序使用的是ISO 8859-1编码,因此应用程序实际上无法正常工作。这意味着è工作,但其他角色,如☺ 没有


问题重述:验证我是否可以持久化UTF-8编码字符串的最低测试是什么?

字符串
实例使用预定义且不可更改的编码(16位字)。
因此,仅从您的服务返回
字符串
可能不足以执行此检查。
您应该尝试返回持久化字符串的字节表示形式(例如字节数组),并将此数组的内容与将使用UTF-8字符集进行字节编码的
“\u263A”
字符串
进行比较

String toSave = "\u263A";  
int id = 123;

// Saves to Database
myComponent.save(id, toSave );

// Retrieve from Database
byte[] actualBytes = myComponent.retrieve(id );

// assertion
byte[] expectedBytes = toSave.getBytes(Charset.forName("UTF-8"));
Assert.assertTrue(Arrays.equals(expectedBytes, actualBytes));

在这里,代码和/或文档审查可能是您的最佳选择。但是,如果您愿意,您可以进行探测。似乎充分的测试是目标,而最小化测试则不那么重要。仅基于对威胁的推测,很难判断什么是充分的测试,但我的建议是:所有代码点,包括U+0000,正确处理“组合字符”

要测试的方法有一个Java字符串作为参数。Java没有“UTF-8编码字符串”:Java的原生文本数据类型使用Unicode字符集的UTF-16编码。这在Java、.NET、JavaScript、VB6、VBA等使用的文本内存表示中很常见,…。UTF-8通常用于流和存储,因此您应该在“保存和获取”的上下文中询问UTF-8。数据库通常提供一个或多个UTF-8、3字节受限UTF-8或UTF-16(NVARCHAR)数据类型和排序规则

编码是一个实现细节。如果组件接受Java字符串,它应该为不愿意处理的数据抛出异常,或者正确处理它

“字符”是一个定义不清的术语。Unicode代码点的范围从0x0到0x10FFFF-21位。根据Unicode标准版本,某些代码点未分配(也称为“已定义”)。Java数据类型可以处理任何代码点,但有关它们的信息受版本限制。对于Java8。您可以将测试限制为“已定义”的代码点,或执行所有可能的代码点

码点是基本“字符”或“组合字符”。此外,每个代码点正好位于一个Unicode类别中。两个类别用于组合字符。要形成一个字形,一个基本字符后跟零个或多个组合字符。以图形方式布局Graphimes(参见文本)可能很困难,但对于文本存储而言,不破坏代码点序列(以及字节顺序,如果适用)所需的一切

因此,这里有一个非最小的,有点全面的测试:

final Stream<Integer> codepoints = IntStream
    .rangeClosed(Character.MIN_CODE_POINT, Character.MAX_CODE_POINT)
    .filter(cp -> Character.isDefined(cp)) // optional filtering
    .boxed();              
final int[] combiningCategories = { 
    Character.COMBINING_SPACING_MARK, 
    Character.ENCLOSING_MARK 
};
final Map<Boolean, List<Integer>> partitionedCodepoints = codepoints
    .collect(Collectors.partitioningBy(cp -> 
        Arrays.binarySearch(combiningCategories, Character.getType(cp)) < 0));
final Integer[] baseCodepoints = partitionedCodepoints.get(true)
    .toArray(new Integer[0]); 
final Integer[] combiningCodepoints = partitionedCodepoints.get(false)
    .toArray(new Integer[0]);
final int baseLength = baseCodepoints.length;
final int combiningLength = combiningCodepoints.length;
final StringBuilder graphemes = new StringBuilder();
for (int i = 0; i < baseLength; i++) {
    graphemes.append(Character.toChars(baseCodepoints[i])); 
    graphemes.append(Character.toChars(combiningCodepoints[i % combiningLength])); 
}
final String test = graphemes.toString();
final byte[] testUTF8 = StandardCharsets.UTF_8.encode(test).array();

// Java 8 counts for when filtering by Character.isDefined 
assertEquals(736681, test.length());  // number of UTF-16 code units
assertEquals(3241399, testUTF8.length); // number of UTF-8 code units
final Stream codepoints=IntStream
.rangeClosed(Character.MIN\u CODE\u POINT,Character.MAX\u CODE\u POINT)
.filter(cp->Character.isDefined(cp))//可选筛选
.boxed();
final int[]组合类别={
字符、间距和标记,
字符.封闭标记
};
最终地图分区编码点=编码点
.collect(收集器)。分区依据(cp->
二进制搜索(组合类别,Character.getType(cp))<0);
最终整数[]baseCodepoints=partitionedCodepoints.get(true)
.toArray(新整数[0]);
最终整数[]combiningCodepoints=partitionedCodepoints.get(false)
.toArray(新整数[0]);
最终int baseLength=baseCodepoints.length;
最终int combiningLength=combiningCodepoints.length;
最终StringBuilder graphemes=新StringBuilder();
对于(int i=0;i
如果您的组件只能存储和检索字符串,那么您需要做的就是确保在与java的Unicode字符串和组件存储的UTF-8字符串的转换过程中不会丢失任何内容

这将涉及从每个UTF-8代码点长度中至少检查一个字符。因此,我建议检查:

  • US-ASCII集合中的一个字符(1字节长的代码点),然后

  • 希腊语中的一个字符,(2字节长的代码点)和

  • 来自中文的一个字符(3字节长的代码点。)

  • 理论上,您还需要使用emoji(4字节长的代码点)进行检查,尽管这些代码点不能用java的Unicode字符串表示,所以这一点没有实际意义

一个有用的额外测试是尝试将上述每种情况中的至少一个字符组合在一起的字符串,以确保不同代码点长度的字符可以在同一字符串中共存

(如果您的组件除了存储和检索字符串(如搜索字符串)之外还做其他事情,那么事情可能会变得更复杂,但在我看来,您明确避免询问这一点。)

我相信黑盒测试是唯一有意义的测试,