如何用JUnit测试Jackson JsonAnySetter注解的调用情况?
如何测试Jackson @JsonAnySetter处理未定义属性的日志功能
这个问题很实用!要验证你的Book类中@JsonAnySetter的日志记录逻辑,我们可以结合JUnit 5、Jackson的ObjectMapper,再配合日志捕获工具来确认未定义属性是否触发了预期的警告日志。下面给你两种常用的测试方案:
方案一:使用slf4j-test直接捕获日志
slf4j-test是SLF4J官方提供的测试库,可以方便地捕获和验证日志输出,不需要额外的mock操作。
步骤1:添加依赖(以Maven为例)
在你的pom.xml中加入slf4j-test依赖:
<dependency> <groupId>uk.org.lidalia</groupId> <artifactId>slf4j-test</artifactId> <version>1.2.0</version> <scope>test</scope> </dependency>
步骤2:编写测试用例
import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import uk.org.lidalia.slf4jtest.TestLogger; import uk.org.lidalia.slf4jtest.TestLoggerFactory; import java.util.List; import static org.junit.jupiter.api.Assertions.*; import static uk.org.lidalia.slf4jtest.LoggingEvent.warn; class BookTest { // 初始化Jackson的ObjectMapper private final ObjectMapper objectMapper = new ObjectMapper(); // 获取Book类对应的测试日志实例 private final TestLogger testLogger = TestLoggerFactory.getTestLogger(Book.class); @Test void shouldLogWarningForUndefinedProperties() throws Exception { // 准备包含未定义属性的JSON数据 String jsonWithUnknownFields = """ { "titleId": "BK-001", "bookName": "Effective Java", "authors": ["Joshua Bloch"], "publisher": "Addison-Wesley", "publicationYear": 2008 } """; // 执行反序列化操作 Book book = objectMapper.readValue(jsonWithUnknownFields, Book.class); // 先验证已知属性是否正确反序列化(确保基础功能正常) assertEquals("BK-001", book.getTitleId()); assertEquals("Effective Java", book.getBookName()); assertEquals(List.of("Joshua Bloch"), book.getAuthors()); // 验证未定义属性是否触发了警告日志 assertTrue(testLogger.contains(warn("Received a key which hasn't been mapped. Key: publisher, Value: Addison-Wesley"))); assertTrue(testLogger.contains(warn("Received a key which hasn't been mapped. Key: publicationYear, Value: 2008"))); } }
方案二:使用Mockito验证日志输出
如果你已经在项目中使用Mockito,也可以通过mock日志对象来验证警告是否被调用。需要注意的是,由于@Slf4j生成的是private static final类型的日志对象,我们需要通过反射来替换它。
步骤1:编写测试用例
import com.fasterxml.jackson.databind.ObjectMapper; import org.junit.jupiter.api.Test; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.lang.reflect.Field; import java.util.List; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.verify; class BookTestWithMockito { private final ObjectMapper objectMapper = new ObjectMapper(); @Test void shouldTriggerWarningLogForUnknownProperties() throws Exception { // 创建mock的Logger对象 Logger mockLog = mock(Logger.class); // 通过反射替换Book类中的静态log字段 Field logField = Book.class.getDeclaredField("log"); logField.setAccessible(true); logField.set(null, mockLog); // 静态字段传入null作为实例参数 // 准备测试用的JSON数据 String jsonWithUnknownFields = """ { "titleId": "BK-002", "bookName": "Clean Code", "authors": ["Robert C. Martin"], "pages": 464 } """; // 执行反序列化 Book book = objectMapper.readValue(jsonWithUnknownFields, Book.class); // 验证已知属性反序列化正确 assertEquals("BK-002", book.getTitleId()); assertEquals("Clean Code", book.getBookName()); assertEquals(List.of("Robert C. Martin"), book.getAuthors()); // 验证警告日志是否被调用 verify(mockLog).warn("Received a key which hasn't been mapped. Key: {}, Value: {}", "pages", 464); } }
额外注意事项
- 由于你的
Book类使用了@Value和@Builder,确保Jackson能正确处理不可变类的反序列化。如果遇到反序列化失败的问题,可以添加jackson-module-parameter-names依赖,并确保ObjectMapper启用了参数名称模块。 - 测试时尽量覆盖多种类型的未定义属性(比如字符串、数字、数组等),确保
@JsonAnySetter能处理不同类型的value参数。
内容的提问来源于stack exchange,提问作者user1692342
相关产品推荐
相关产品推荐

