shinytest通过testthat运行时JSON文件顺序差异问题咨询
关于shinytest结合testthat时JSON数组顺序差异的问题解答
是否为已知问题
这是shinytest与testthat集成场景下的已知兼容细节,并非软件bug,但属于开发者容易踩的“坑”,相关讨论在shinytest的社区议题中能找到记录。
为何仅在testthat中出现
直接调用shinytest::testApp()时,shinytest内部对JSON文件的比较是语义化的:它会先把JSON解析成R对象,再对数组类结构做无序对比,不会因为元素顺序不同判定为差异。
但用testthat::expect_pass()包裹后,testthat的断言框架会改变测试结果的捕获与判定逻辑——此时shinytest的默认比较逻辑被覆盖,转而对JSON的序列化字符串做严格的逐字符对比。而JSON数组的元素顺序会直接体现在序列化后的字符串中,自然就会被判定为差异。
忽略顺序比较JSON的方法
有三种可行方案:
1. 自定义JSON比较函数
给testApp()传入compare参数,替换默认的文件对比逻辑,先解析JSON为R对象,再用支持忽略顺序的工具做对比:
custom_json_compare <- function(ref_path, current_path) { # 仅处理JSON文件 if (tolower(tools::file_ext(ref_path)) != "json" || tolower(tools::file_ext(current_path)) != "json") { return(shinytest::defaultCompare(ref_path, current_path)) } # 解析JSON为R对象 ref_json <- jsonlite::fromJSON(ref_path, simplifyVector = FALSE) current_json <- jsonlite::fromJSON(current_path, simplifyVector = FALSE) # 用waldo做忽略顺序的对比 diffs <- waldo::compare(ref_json, current_json, ignore_order = TRUE) return(length(diffs) == 0) } # 在testthat测试中使用 test_that("Shiny app功能测试", { expect_pass(shinytest::testApp("your_app_path", compare = custom_json_compare)) })
2. 标准化参考JSON的生成
在生成参考JSON文件时,强制对数组元素排序,确保序列化后的字符串顺序一致:
# 生成参考JSON时添加排序参数 jsonlite::write_json(your_data, "tests/testthat/reference.json", pretty = TRUE, sort.names = TRUE, auto_unbox = TRUE)
这样后续测试时,即使app输出的JSON数组顺序不同,序列化后也会和参考文件一致。
3. 迁移到shinytest2
shinytest2是shinytest的官方升级版本,专门优化了与testthat的集成逻辑,默认就会对JSON数组做语义化对比(忽略顺序),这类兼容性问题已经被修复。如果项目允许,直接切换到shinytest2是最省心的方案。
内容的提问来源于stack exchange,提问作者Stéphane Laurent
相关产品推荐
相关产品推荐

