首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >根据xsd模式符合xml元素的单元测试函数。

根据xsd模式符合xml元素的单元测试函数。
EN

Stack Overflow用户
提问于 2022-01-21 12:59:01
回答 1查看 95关注 0票数 0

例如,为了简单起见,我们在xsd中定义了三个元素"a“、"b”和"c“,其中:

  • "a“和"b”是"c“的孩子,
  • 元素"c“本身也可以是子元素,
  • 元素"a“和"b”没有childs。

我编写了一个函数来“扫描”一个xml,如果它检测到错误的元素,它将尝试--如果可能的话--根据xsd对它们进行整合。主要代码是:

代码语言:javascript
复制
# conformity.py

from lxml.etree import Element

def conform_element_a(root: Element) -> Element | None:
   # If some attributes of the root as element "a" 
   # are not compliant, apply some transformations
   # to these in order to conform root.
   # If transformations are possible, return root.
   # If transformations are not possible, return None.

def conform_element_b(root: Element) -> Element | None:
   # same as before

def conform_element_c(root: Element):
   # conform child "a"
   a = root.find("a")
   if a is not None:
      a = conform_element_a(a)
      if a is None:
         root.remove(a)
   # conform child "b"
   b = root.find("b")
   if b is not None:
      b = conform_element_b(b)
      if b is None:
         root.remove(b)
   # conform child "c"
   c = root.find("c")
   if c is not None:
      c = conform_element_c(c)

现在,我想测试这三个功能。为了测试conform_element_aconform_element_b,我考虑使用工厂作为夹具,如下所示

代码语言:javascript
复制
import pytest
from lxml import etree
from mypackage.utils import tree_equality
from mypackage.conformity import conform_element_a

# Factory
@pytest.fixture
def make_element_a():
    def _make_element_a(**kwargs):
        # build an element "a"
        # according to kwargs
        return a

    return _make_element_a


class TestConformA:
    @pytest.mark.parametrize("attrib_1", [...])
    @pytest.mark.parametrize("attrib_2", [...])
    def test_none_case(make_element_a, attrib_1, attrib_2):
        a = make_element_a(attrib_1, attrib_2)
        a = conform_element_a(a)
        assert a is None
    
    @pytest.mark.parametrize("attrib_1, exp1", [...])
    @pytest.mark.parametrize("attrib_2, exp2", [...])
    def test_not_none(make_element, attrib_1, attrib_2, exp1, exp2):
        a = make_element_a(attrib_1, attrib_2)
        expected = make_element_a(exp1, exp2)
        a = conform_element_a(a)
        assert tree_equality(a, expected)

两个问题:

  1. 我想知道这不是测试conform_element_aconform_element_b的好方法。这里我提出了两个属性,例如目的,但在现实中有更多,它可以很快变得冗长。
  2. 我不知道如何测试函数conform_element_c。以前,只存在作为参数的属性。但是现在有了属性和孩子!尤其是"c“本身可以是一个孩子的情况。
EN

回答 1

Stack Overflow用户

发布于 2022-01-22 23:41:21

我的一些主观想法:

  • 从您所展示的情况来看,make_element_a()应该只是一个常规函数。没有理由让它成为固定的东西。
  • 既然所有的函数都在XML元素上运行,为什么不让测试参数成为XML片段呢?您可以编写一个简单的助手函数来将这些片段解析为元素,这将容纳对"a“、"b”和"c“的测试。
  • 我不认为这样嵌套@pytest.mark.parametrize装饰师是个好主意。这样做很难将预期投入与预期产出明确联系起来。我要做的唯一一次是当一些参数与预期的输出没有关系时,例如测试多个工厂,这些工厂都应该构造相同的对象。

考虑到上述情况,下面是我如何编写这些测试的方法:

代码语言:javascript
复制
import pytest
from mypackage.utils import elem_from_str, tree_equality
from mypackage.conformity import conform_element_a

@pytest.mark.parametrize(
    'given, expected', [
        (
            '<a/>',
            '<a/>',
        ), (
            '<a x=1/>',
            '<a x=2/>',
        ), (
            '<a y=1/>',
            None,
        ),
    ]
)
def test_conform_element_a(given, expected):
    given = elem_from_str(given)
    expected = elem_from_str(expected)
    conformed = conform_element_a(given)
    assert tree_equality(conformed, expected)

使用XML编码测试参数的一个缺点是,您可能最终会得到多行XML片段,而多行字符串确实会使参数列表难以读取。我编写了一个名为https://parametrize-from-file.readthedocs.io/en/latest/index.html的包,它可以通过(顾名思义)帮助您在外部文件中指定参数。支持所有常见的配置文件格式(YAML、TOML、JSON),但在我看来,多行字符串的最佳格式是嵌套文本

下面是使用这种方法进行测试的方式:

代码语言:javascript
复制
# test_conform_element.nt
test_conform_element_c:
  -
    id: no-children
    given: <c/>
    expected: <c/>
  -
    id: child-ab
    given:
      > <c>
      >  <a/>
      >  <b/>
      > </c>
    expected:
      > <c>
      >  <a/>
      >  <b/>
      > </c>
  -
    id: child-c-recursive
    given:
      > <c>
      >  <c>
      >   <a>
      >   <b>
      >  </c>
      > </c>
    expected:
      > <c>
      >  <c>
      >   <a>
      >   <b>
      >  </c>
      > </c>
代码语言:javascript
复制
# test_conform_element.py
import parametrize_from_file
from mypackage.utils import elem_from_str, tree_equality
from mypackage.conformity import conform_element_c

@parametrize_from_file
def test_conform_element_c(given, expected):
    given = elem_from_str(given)
    expected = elem_from_str(expected)
    conformed = conform_element_c(given)
    assert tree_equality(conformed, expected)

我认为这使得测试代码和测试参数更容易阅读。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/70801678

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档