Java 验证组件是否可以保存/检索UTF8编码字符串的最低测试是什么
我正在集成测试一个组件。该组件允许您保存和获取字符串 我想验证组件是否正确处理UTF-8字符。验证这一点所需的最低测试是什么 我认为这样做是一个好的开始: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
// 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字符串表示,所以这一点没有实际意义