目录
JSONassert
1、概述
在开发过程中,我们经常需要验证返回结果的正确性。RESTful API接口,返回的数据通常是JSON格式,因此需要一种简单的方法来检查JSON的结构和内容是否符合预期。Java JSONassert是帮助我们实现这一目标的常用工具。
Maven依赖:
<dependency>
<groupId>org.skyscreamer</groupId>
<artifactId>jsonassert</artifactId>
<version>1.5.0</version>
<scope>test</scope>
</dependency>
语法很简单,与JUnit Assert类似:
JSONAssert.assertEquals(预期JSON ,实际JSON , strictMode );
JSONassert有如下4种比较模式,这些不同的模式为JSON的测试比较定义了不同的行为。每个模式封装了两个底层行为:可扩展性
和严格排序
- LENIENT:宽容模式,即实际JSON包含扩展字段,数组顺序不一致也可以通过测试
- STRICT:严格模式,即实际JSON不可扩展,数组严格排序才可以通过测试
- NON_EXTENSIBLE:非扩展模式,即实际JSON不可扩展,数组顺序不一致也可以通过测试
- STRICT_ORDER:严格排序模式,即实际JSON可扩展,但数组严格排序才可以通过测试
2、使用示例
2.1、LENIENT模式
@Test
public void lenientTest() throws JSONException {
String actual = "{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}", actual, JSONCompareMode.LENIENT);
//宽容模式下,即使实际JSON包含扩展字段,数组顺序不一致也可以通过测试
String actualJsonStr = "{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"scores\": [88, 77, 99]}", actualJsonStr, JSONCompareMode.LENIENT);
}
2.2、STRICT模式
@Test
public void strictTest() throws JSONException {
String actual = "{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}", actual, JSONCompareMode.STRICT);
//严格模式下,实际JSON包含扩展字段age、scores,测试不通过
String actualJsonStr = "{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\"}", actualJsonStr, JSONCompareMode.STRICT);
//严格模式下,实际JSON数组字段顺序不一致,测试不通过
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [99, 88, 77]}", actualJsonStr, JSONCompareMode.STRICT);
}
2.3、NON_EXTENSIBLE模式
@Test
public void nonExtensibleTest() throws JSONException {
String actual = "{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}", actual, JSONCompareMode.NON_EXTENSIBLE);
//非扩展模式下,数组顺序不一致也可以通过测试
String actualJsonStr = "{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [99, 88, 77]}", actualJsonStr, JSONCompareMode.NON_EXTENSIBLE);
//非扩展模式下,实际JSON有扩展字段无法通过测试
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\"}", actualJsonStr, JSONCompareMode.NON_EXTENSIBLE);
}
2.4、STRICT_ORDER模式
@Test
public void strictOrderTest() throws JSONException {
String actual = "{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"scores\": [77, 88, 99]}", actual, JSONCompareMode.STRICT_ORDER);
//严格排序模式下,实际JSON有扩展字段也可通过测试
String actualJsonStr = "{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [77, 88, 99]}";
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\"}", actualJsonStr, JSONCompareMode.STRICT_ORDER);
//严格排序模式下,数组顺序不一致,无法通过测试
JSONAssert.assertEquals("{\"id\": 123, \"name\": \"tom\", \"age\": 18, \"scores\": [99, 88, 77]}", actualJsonStr, JSONCompareMode.STRICT_ORDER);
}
2.5、逻辑比较
JSONAssert对数据进行逻辑比较。 这意味着在处理JSON对象时,元素的顺序无关紧要:
@Test
public void logicTest() throws JSONException {
//无论是否严格,以下两种模式都会通过
String result = "{\"id\": 1, \"name\": \"tom\"}";
JSONAssert.assertEquals("{\"name\": \"tom\", \"id\": 1}", result, JSONCompareMode.STRICT);
JSONAssert.assertEquals("{\"name\": \"tom\", \"id\": 1}", result, JSONCompareMode.LENIENT);
//可以通过对同一值使用不同的类型来演示逻辑比较的另一个示例
JSONObject expected = new JSONObject();
expected.put("id", Integer.valueOf(12345));
JSONObject actual = new JSONObject();
actual.put("id", Double.valueOf(12345));
//无论类型如何,逻辑值值都是12345,所以测试通过
JSONAssert.assertEquals(expected, actual, JSONCompareMode.LENIENT);
//即使在嵌套对象的情况下,也是如此
//language=JSON
String actualJsonStr = "{\"id\": 1, \"name\": \"tom\", \"adress\": {\"city\": \"Hollywood\",\"state\": \"LA\"}}";
String expectedJsonStr = "{\"id\": 1, \"name\": \"tom\", \"adress\": {\"city\": \"Hollywood\",\"state\": \"LA\"}}";
JSONAssert.assertEquals(expectedJsonStr, actualJsonStr, JSONCompareMode.LENIENT);
}
2.6、带有指定消息的断言
所有assertEquals()和assertNotEquals()方法均接受String消息作为第一个参数。 该消息通过在测试失败的情况下提供有意义的消息来为我们的测试用例提供一些自定义:
@Test
public void messageTest() throws JSONException {
//language=JSON
String actual = "{\"id\": 123, \"name\": \"tom\"}";
String failureMessage = "Only one field is expected: name";
try {
JSONAssert.assertEquals(failureMessage, "{\"name\": \"tom\"}", actual, JSONCompareMode.STRICT);
} catch (AssertionError e) {
Assertions.assertThat(e.getMessage()).containsIgnoringCase(failureMessage);
}
}
2.7、JSON数组
第一个区别是在STRICT比较模式下,数组中元素的顺序必须完全相同。 但是,对于LENIENT比较模式,顺序无关紧要:
@Test
public void arrayTest1() throws JSONException {
String result = "[\"Alex\", \"Barbera\", \"Charlie\", \"Xavier\"]";
JSONAssert.assertEquals("[\"Charlie\", \"Alex\", \"Xavier\", \"Barbera\"]", result, JSONCompareMode.LENIENT);
JSONAssert.assertEquals("[\"Alex\", \"Barbera\", \"Charlie\", \"Xavier\"]", result, JSONCompareMode.STRICT);
JSONAssert.assertNotEquals("[\"Charlie\", \"Alex\", \"Xavier\", \"Barbera\"]", result, JSONCompareMode.STRICT);
}
另一个区别是在处理JSON数组时不允许使用扩展元素:
@Test
public void arrayTest2() throws JSONException {
String result ="[1,2,3,4,5]";
//即使使用LENIENT比较模式,期望数组中的项目也必须与实际数组中的项目完全匹配。 添加或删除甚至单个元素都将导致失败
JSONAssert.assertEquals("[1,2,3,4,5]", result, JSONCompareMode.LENIENT);
JSONAssert.assertNotEquals("[1,2,3]", result, JSONCompareMode.LENIENT);
JSONAssert.assertNotEquals("[1,2,3,4,5,6]", result, JSONCompareMode.LENIENT);
}
使用ArraySizeComparator验证数组大小:
@Test
public void arrayTest3() throws JSONException {
String names = "{\"names\":[\"Alex\", \"Barbera\", \"Charlie\", \"Xavier\"]}";
//{names:[4]}指定预期数组大小为4
JSONAssert.assertEquals(
"{names:[4]}",
names,
new ArraySizeComparator(JSONCompareMode.LENIENT));
//{names:[3,5]}指定预期数组大小为3和5之间
JSONAssert.assertEquals(
"{names:[3,5]}",
names,
new ArraySizeComparator(JSONCompareMode.LENIENT));
}
2.8、正则表达式
@Test
public void regularTest() throws JSONException {
JSONAssert.assertEquals("{\"entry\":{\"id\":x}}","{\"entry\":{\"id\":1, \"id\":2}}",
new CustomComparator(
JSONCompareMode.STRICT,
new Customization("entry.id",
new RegularExpressionValueMatcher<Object>("\\d"))));
JSONAssert.assertNotEquals("{\"entry\":{\"id\":x}}","{\"entry\":{\"id\":1, \"id\":\"as\"}}",
new CustomComparator(JSONCompareMode.STRICT,
new Customization("entry.id",
new RegularExpressionValueMatcher<Object>("\\d"))));
}