You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在测试模块中修改XQuery常量模块变量以测试库函数?

问题:如何在XQuery测试中修改常量模块的变量以测试依赖函数?

我有一个库模块(lib),其函数依赖另一个常量模块(const)中的变量。现在想在测试模块中测试lib的函数,尝试修改const模块的变量来进行特定测试,但尝试重置$con:numbers或用replace node语句修改都无效。想请教是否可以修改$const:numbers,让后续调用lib:inc5时使用修改后的值?

相关代码如下:

const模块

xquery version "3.1" encoding "utf-8";

module namespace const = "Constant";

declare variable $const:numbers:=
<numbers>
  <value s='one'>1</value>
  <value s='two'>2</value>
  <value s='three'>3</value>
  <value s='four'>4</value>
  <value s='five'>5</value>
  <value s='other'></value>
</numbers>;

lib模块

xquery version "3.1" encoding "utf-8";

module namespace lib = "Library";

import module namespace con="Constant" at "const.xqm";

declare function lib:inc5($val as xs:string) as xs:integer {
  5+xs:integer($con:numbers//value[@s=$val])
};

test模块

xquery version "3.1" encoding "utf-8";

module namespace test='http://basex.org/modules/xqunit-tests';

import module namespace con="Constant" at "const.xqm";
import module namespace lib="Library" at "lib.xqm";

declare %unit:test function test:inc5_add_one() {
  unit:assert-equals(lib:inc5('one'), 6)
};

declare %unit:test function test:inc5_set_other_as_10_add_ten() {
  (: replace node $con:numbers//value[@s='other'] with <value s='ten'>10</value> :)
  (: 
  $con:numbers=<numbers>
    <value s='one'>1</value>
    <value s='two'>2</value>
    <value s='three'>3</value>
    <value s='four'>4</value>
    <value s='five'>5</value>
    <value s='ten'>10</value>
  </numbers>,
  :)
  unit:assert-equals(lib:inc5('ten'), 15)
};

解答

核心原因:默认模块变量是只读的

XQuery中,用declare variable声明的模块全局变量默认是只读的,无法直接赋值修改,也不能通过普通的节点更新语句修改(除非显式声明为可更新)。这就是你尝试修改无效的原因。

推荐方案:重构lib函数,增加可选数据源参数

这是最干净、无副作用的测试方式——让lib:inc5函数接受一个可选的$numbers参数,默认使用常量模块的值,测试时传入自定义的测试数据即可:

修改后的lib模块

xquery version "3.1" encoding "utf-8";

module namespace lib = "Library";

import module namespace con="Constant" at "const.xqm";

declare function lib:inc5($val as xs:string, $numbers as node()? := $con:numbers) as xs:integer {
  5 + xs:integer($numbers//value[@s=$val])
};

修改后的测试函数

declare %unit:test function test:inc5_set_other_as_10_add_ten() {
  let $test-numbers := 
    <numbers>
      <value s='one'>1</value>
      <value s='two'>2</value>
      <value s='three'>3</value>
      <value s='four'>4</value>
      <value s='five'>5</value>
      <value s='ten'>10</value>
    </numbers>
  return unit:assert-equals(lib:inc5('ten', $test-numbers), 15)
};

这种方式不修改全局状态,测试之间完全隔离,不会互相干扰,也不需要依赖处理器的更新特性。

备选方案:使用可更新变量(需处理器支持)

如果你的XQuery处理器(比如BaseX)支持更新特性,可以将常量模块的变量声明为可更新的,然后在测试中修改并恢复:

修改后的const模块

xquery version "3.1" encoding "utf-8";

module namespace const = "Constant";

declare %updating variable $const:numbers :=
<numbers>
  <value s='one'>1</value>
  <value s='two'>2</value>
  <value s='three'>3</value>
  <value s='four'>4</value>
  <value s='five'>5</value>
  <value s='other'></value>
</numbers>;

修改后的测试函数

declare %unit:test function test:inc5_set_other_as_10_add_ten() {
  (: 先保存原始值,测试后恢复,避免影响其他测试 :)
  let $original := $con:numbers
  do {
    (: 替换目标节点 :)
    replace node $con:numbers//value[@s='other'] with <value s='ten'>10</value>,
    unit:assert-equals(lib:inc5('ten'), 15),
    (: 恢复原始状态 :)
    replace node $con:numbers with $original
  }
};

注意:这种方式会修改全局变量状态,必须在测试后恢复原始值,否则会干扰其他测试用例,不推荐作为首选方案。


内容的提问来源于stack exchange,提问作者user18451290

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 09:40:42