例如,为了简单起见,我们在xsd中定义了三个元素"a“、"b”和"c“,其中:
我编写了一个函数来“扫描”一个xml,如果它检测到错误的元素,它将尝试--如果可能的话--根据xsd对它们进行整合。主要代码是:
# 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_a和conform_element_b,我考虑使用工厂作为夹具,如下所示
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)两个问题:
conform_element_a和conform_element_b的好方法。这里我提出了两个属性,例如目的,但在现实中有更多,它可以很快变得冗长。conform_element_c。以前,只存在作为参数的属性。但是现在有了属性和孩子!尤其是"c“本身可以是一个孩子的情况。发布于 2022-01-22 23:41:21
我的一些主观想法:
make_element_a()应该只是一个常规函数。没有理由让它成为固定的东西。@pytest.mark.parametrize装饰师是个好主意。这样做很难将预期投入与预期产出明确联系起来。我要做的唯一一次是当一些参数与预期的输出没有关系时,例如测试多个工厂,这些工厂都应该构造相同的对象。考虑到上述情况,下面是我如何编写这些测试的方法:
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),但在我看来,多行字符串的最佳格式是嵌套文本。
下面是使用这种方法进行测试的方式:
# 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># 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)我认为这使得测试代码和测试参数更容易阅读。
https://stackoverflow.com/questions/70801678
复制相似问题