单元测试与pytest的比较

129

在单元测试中,我可以在一个类中使用setUp方法设置变量,然后该类的方法可以选择使用任何它想要使用的变量...

在unittest中,我可以在一个类中通过使用setUp方法来设定变量,然后该类中的方法可以选择使用其中任何一个变量...

class test_class(unittest.TestCase):
    def setUp(self):        
        self.varA = 1
        self.varB = 2
        self.varC = 3
        self.modified_varA = 2

    def test_1(self):
        do_something_with_self.varA, self.varB

    def test_2(self):
        do_something_with_self_modified_varA, self.varC

因此,在unittest中,很容易将一堆测试放在一个类中,并为不同方法使用许多不同的变量(varAvarB)。在pytest中,我创建了一个fixture,而不是像unittest中的class那样,放在conftest.py中,就像这样...

@pytest.fixture(scope="module")
def input1():
    varA = 1
    varB = 2
    return varA, varB

@pytest.fixture(scope="module")
def input2():
    varA = 2
    varC = 3
    return varA, varC

我将这个input1和input2传递给不同文件中的函数(比如说test_this.py)的两个不同函数。以下是基于上述信息的问题...

  1. 由于我不能像在conftest.py中导入那样声明局部变量,因此是否有更好的方法在此处声明不同的变量,以便可以在test_this.py中的不同函数中使用?在我的实际测试中,我有五种不同的变量配置,定义许多不同的固定装置在conftest.py中,并在test_this.py中的五个不同函数中使用它们作为函数参数听起来很痛苦。我宁愿回到unittest类结构,定义我的变量并挑选我想要的。

  2. 我应该只在test_this.py中声明全局变量,并按照自己的方式在函数中使用它们吗?这似乎不太符合Pythonic。这些变量仅由此文件中的函数使用。

  3. 假设我还有test_that.py和test_them.py。如果这些不同文件之间有一些共享变量,我该如何声明它们?只需在所有这些测试文件所在的目录中创建一个名为variables.py的文件,并在需要时进行导入吗?这样我就可以将所有数据保存在单独的文件中。

  4. 是不是pytest不鼓励使用类来组织函数?我在网上读到的每个例子都似乎只使用了一堆带有固定装置的函数。在pytest中定义类和方法以及组织测试的配置是什么?

  5. 我有一个测试场景,需要将一个函数的结果用于另一个函数。在pytest中,我有一个断言位于函数末尾而不是返回值,因此我将无法将此函数用作fixture。我该如何处理这个问题?我知道这不是一个好的实践,我的一个测试依赖于另一个测试,但是否有解决方法?


1
https://docs.pytest.org/en/6.2.x/unittest.html - yucer
2个回答

78

首先,你不仅可以在conftest.py中声明这些fixtures,也可以在任何想要的Python模块中声明。并且你可以导入那个模块。 此外,你可以像使用setUp方法一样使用fixtures:

1)首先,您可以在任何Python模块中声明这些固定装置,而不仅仅是在conftest.py中。您可以导入该模块。 此外,您可以像使用setUp方法一样使用fixture:

@pytest.fixture(scope='class')
def input(request):
    request.cls.varA = 1
    request.cls.varB = 2
    request.cls.varC = 3
    request.cls.modified_varA = 2

@pytest.usefixtures('input')
class TestClass:
    def test_1(self):
        do_something_with_self.varA, self.varB

    def test_2(self):
        do_something_with_self_modified_varA, self.varC

或者您可以在不同的fixture中定义不同的变量:

def fixture_a():
    return varA

def fixture_b():
    return varB

def fixture_c():
    return varC

def fixture_mod_A():
    return modified_varA

或者创建一个夹具,返回所有变量(为什么不呢?) 甚至可以创建一个间接的参数化夹具,按您选择的方式返回变量(相当混乱的方式):

@pytest.fixture()
def parametrized_input(request):
   vars = {'varA': 1, 'varB': 2, 'varC': 3}
   var_names = request.param
   return (vars[var_name] for var_name in var_names)

@pytest.mark.parametrize('parametrized_input', [('varA', 'varC')], indirect=True)
def test_1(parametrized_input)
   varA, varC = parametrized_input
   ...

甚至可以创建一个夹具工厂,可以即时为您创建夹具。如果你只有5个测试和5个变量配置时,它听起来很奇怪,但当你有数百个测试和变量配置时,它就会很有用。

3) 当然可以。但我建议您不要直接导入此文件,而是使用命令行选项指定要导入的文件。在这种情况下,您可以选择另一个带有变量的文件,而不必更改代码。

4) 我在我的测试中使用类,因为我从nosetest迁移过来了。我没有提到在pytest中使用类存在任何问题。

5) 在这种情况下,我建议您执行以下操作:首先创建所需操作的函数:

def some_actions(a, b):
    # some actions here
    ...
    return c

然后在测试和夹具中都使用它:

def test():
    assert some_actions(1,2) == 10

@pytest.fixture()
def some_fixture():
     return some_actions(1,2)

8
谢谢,这对我在从unittest迁移到py.test方面有很大帮助。不过,我有一条评论:我认为应该使用@pytest.mark.usefixtures而不是@pytest.usefixtures - Sven van der Burg

35

我认为Unittest更容易阅读。对于新手测试人员来说,Unittest非常简单。它是开箱即用的。你依赖于Python实现,但未来几年他们不会改变接口。

我喜欢以这样的方式组织我的测试,即每个文件最多只有一个测试。在这种情况下,我不依赖于类...但我从每个测试导入类来做一些事情。

有些网站抱怨在unittest中无法使用颜色。我认为那是个玩笑,因为我的unittests为Jenkins和其他工具创建了JUNIT输出报告。有很棒的工具(甚至只有1个文件)可以将JUNIT转换为网站,这不是测试工具的责任。

此外,有些人抱怨启动unittest需要大量代码。我不同意,只需4行代码就可以创建一个unittest!但是Pytest需要知道所有复杂的注释,这对于简单的Python开发人员来说并不正常。

另一个重要原因是unittest将保持免费。但是,如果出于某种原因想要使用pytest(比如Bitbucket等),则存在将您的测试转换并使代码更不易读的工具。

玩得开心!


46
重要的一个原因是unittest将保持免费。但是,如果出于某些原因(例如Bitbucket),您希望使用pytest,有一些工具可以转换您的测试并使代码变得不那么易读。您是否暗示pytest不会免费?在这里,“免费”指的是没有费用。最后一段对我来说相当困惑。 - baxx
8
我对unittest唯一的抱怨是它使用自定义语法操作,例如self.assertEqual(some_var, 5),而不像pytest那样使用清晰的assert some_var == 5 - ierdna
2
然而,如果您因某些原因(如Bitbucket等)想要使用pytest,则pytest是否与unittest相比更好地集成了Bitbucket? - matthiash
8
最后一条建议“使代码不太易读”有损其他好建议的形象。使用标准库是使用包的一个很好的原因,而且单元测试可以减少很多样板代码,但是“易读性”是非常主观的。 - Davos
5
为什么最后一条评论说“一个重要的原因”——你的理由是什么?Pytest不是免费的吗?它与Bitbucket有什么关系? - Jeppe
显示剩余9条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接