【问题标题】:Persist variable changes between tests in unittest?在unittest中的测试之间保持变量变化?
【发布时间】:2014-02-22 05:44:42
【问题描述】:

如何在 unitttest 中保留从 TestCase 继承的同一对象中所做的更改?

from unittest import TestCase, main as unittest_main


class TestSimpleFoo(TestCase):
    foo = 'bar'

    def setUp(self):
        pass

    def test_a(self):
        self.assertEqual(self.foo, 'bar')
        self.foo = 'can'

    def test_f(self):
        self.assertEqual(self.foo, 'can')


if __name__ == '__main__':
    unittest_main()

即:我希望上面的这两个测试通过

【问题讨论】:

  • 单元测试应该是独立的。 [无论如何,self.foo 指的是一个实例变量,而foo = 'bar'(它所在的位置)分配一个类变量。]
  • 我正在测试 OAuth2; login 设置了一个 access_token,我需要在接下来的几个测试中使用它。
  • 你不能用适当的setUp 创建一个不同的 测试类来模拟适当的access_token 吗? (根据需要让 setUp 调用 OAuth;此时更多的集成测试.. 但请认为 setUp 不可能是错误的,否则其他 TestCase 会失败。)
  • stackoverflow.com/questions/3843171/… - 不是真正的答案,而是一些建议和链接。
  • 考虑调查setUpClass()。当您的课程被调用时,它会运行一次。您可以使用它来设置多个测试所需的变量。

标签: python unit-testing persistence testcase python-unittest


【解决方案1】:

正如一些 cmets 所回应的那样,以这种方式构建测试可能是测试本身的设计缺陷,您应该考虑重新构建它们。但是,如果您想这样做并依赖于您使用的测试运行程序按字母顺序(看似)执行它们的事实,那么我建议如下。

与@Matthias 所说的类似,但对于您以后可能决定从该类继承的情况,我会做一件事。

from unittest import TestCase, main as unittest_main


class TestSimpleFoo(TestCase):
    foo = 'bar'

    def setUp(self):
        pass

    def test_a(self):
        self.assertEqual(self.__class__.foo, 'bar')
        self.__class__.foo = 'can'

    def test_f(self):
        self.assertEqual(self.__class__.foo, 'can')


if __name__ == '__main__':
    unittest_main()

此答案与您接受的@Matthias 答案之间的区别在于该类的显式声明与所述类引用的查找。

TestSimpleFoo vs self.__class__

我更喜欢动态性,因此我可以稍后继承测试并背靠背运行两个测试类,并且两者之间没有任何交叉。因为如果您选择从此类继承,显式命名类引用将导致两个测试类都针对该引用而不是它们各自的类运行。

【讨论】:

  • 是的,我一直在使用整个 def test_0 语法来克服排序问题。当然,将使用__class__;这也更简洁=)。是的,我可以重组我的测试;但宁愿一个更干净的测试界面。
【解决方案2】:

我喜欢你自己的简单答案,但如果你想保持不同的单元测试:

显然 unittest 使用新的 TestCase 实例运行单独的测试。好吧,只需将要持久化的对象绑定到 self 之外的其他对象。例如:

from unittest import TestCase, main as unittest_main


class TestSimpleFoo(TestCase):

    def setUp(self):
        pass

    def test_a(self):
        TestSimpleFoo.foo = 'can'

    def test_f(self):
        self.assertEqual(TestSimpleFoo.foo, 'can')


if __name__ == '__main__':
    unittest_main()

您可能也对 setUpClass 和 tearDownClass 感兴趣: https://docs.python.org/3/library/unittest.html#setupclass-and-teardownclass

还要注意单元测试的执行顺序: https://docs.python.org/2/library/unittest.html#unittest.TestLoader.sortTestMethodsUsing

【讨论】:

  • 谢谢,我已经将@tearDownClass 用于我的unregister 功能。您建议的有趣方法:会试一试。
  • 你不应该这样做。如果您的测试运行者决定在单独的进程中运行测试(例如将负载分配到多台计算机)怎么办?测试运行者对单元测试有一些假设,你不应该违反它们。正如 Ned 所说,A T 的答案是正确的做法。
  • 我不喜欢这个解决方案,没有必要以这种方式构建你的测试。我认为最可行的解决方案是重组/设计您的测试,使它们符合 python 单元测试的概念。
  • @brunsgaard 我可以理解。这是一种解决方法,因此不是很漂亮。根本问题是python单元测试不支持测试序列的概念。测试序列 - 当然 - 只是独立单元测试的次优解决方案,但面对测试运行时间和测试可维护性之间的权衡,这是一个有效的解决方案。
  • @brunsgaard Thx,“在模块中的测试之间共享夹具”正是 OP 所需要的:pytest.org/latest/…
【解决方案3】:

想不通;所以最终用多个非 test_ 前缀函数破解了它:

def test_password_credentials_grant(self):
    for user in self.user_mocks:
        self.register(user)
        self.login(user)
        self.access_token(user, self.assertEqual)  # Ensures access_token is generated+valid
        self.logout(user)
        self.access_token(user, self.assertNotEqual)  # Ensures access_token is now invalid
        self.unregister(user)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2016-04-01
    • 2015-09-20
    • 2020-02-12
    • 2015-07-11
    相关资源
    最近更新 更多