[python] 기본 및 하위 클래스를 사용한 Python 단위 테스트

현재 공통 테스트 세트를 공유하는 몇 가지 단위 테스트가 있습니다. 예를 들면 다음과 같습니다.

import unittest

class BaseTest(unittest.TestCase):

    def testCommon(self):
        print 'Calling BaseTest:testCommon'
        value = 5
        self.assertEquals(value, 5)

class SubTest1(BaseTest):

    def testSub1(self):
        print 'Calling SubTest1:testSub1'
        sub = 3
        self.assertEquals(sub, 3)


class SubTest2(BaseTest):

    def testSub2(self):
        print 'Calling SubTest2:testSub2'
        sub = 4
        self.assertEquals(sub, 4)

if __name__ == '__main__':
    unittest.main()

위의 결과는 다음과 같습니다.

Calling BaseTest:testCommon
.Calling BaseTest:testCommon
.Calling SubTest1:testSub1
.Calling BaseTest:testCommon
.Calling SubTest2:testSub2
.
----------------------------------------------------------------------
Ran 5 tests in 0.000s

OK

첫 번째 testCommon가 호출되지 않도록 위의 내용을 다시 쓰는 방법이 있습니까?

편집 :
위의 5 가지 테스트를 실행하는 대신 SubTest1에서 2 개, SubTest2에서 2 개를 4 개만 실행하려고합니다. 파이썬 unittest는 독자적인 BaseTest를 자체적으로 실행하고있는 것으로 보이며 그 발생을 막기위한 메커니즘이 필요합니다.



답변

다중 상속을 사용하므로 일반적인 테스트를 수행하는 클래스 자체는 TestCase에서 상속되지 않습니다.

import unittest

class CommonTests(object):
    def testCommon(self):
        print 'Calling BaseTest:testCommon'
        value = 5
        self.assertEquals(value, 5)

class SubTest1(unittest.TestCase, CommonTests):

    def testSub1(self):
        print 'Calling SubTest1:testSub1'
        sub = 3
        self.assertEquals(sub, 3)


class SubTest2(unittest.TestCase, CommonTests):

    def testSub2(self):
        print 'Calling SubTest2:testSub2'
        sub = 4
        self.assertEquals(sub, 4)

if __name__ == '__main__':
    unittest.main()


답변

다중 상속을 사용하지 마십시오 . 나중에 물릴 것 입니다.

대신 기본 클래스를 별도의 모듈로 옮기거나 빈 클래스로 래핑 할 수 있습니다.

class BaseTestCases:

    class BaseTest(unittest.TestCase):

        def testCommon(self):
            print('Calling BaseTest:testCommon')
            value = 5
            self.assertEqual(value, 5)


class SubTest1(BaseTestCases.BaseTest):

    def testSub1(self):
        print('Calling SubTest1:testSub1')
        sub = 3
        self.assertEqual(sub, 3)


class SubTest2(BaseTestCases.BaseTest):

    def testSub2(self):
        print('Calling SubTest2:testSub2')
        sub = 4
        self.assertEqual(sub, 4)

if __name__ == '__main__':
    unittest.main()

출력 :

Calling BaseTest:testCommon
.Calling SubTest1:testSub1
.Calling BaseTest:testCommon
.Calling SubTest2:testSub2
.
----------------------------------------------------------------------
Ran 4 tests in 0.001s

OK


답변

단일 명령으로이 문제를 해결할 수 있습니다.

del(BaseTest)

따라서 코드는 다음과 같습니다.

import unittest

class BaseTest(unittest.TestCase):

    def testCommon(self):
        print 'Calling BaseTest:testCommon'
        value = 5
        self.assertEquals(value, 5)

class SubTest1(BaseTest):

    def testSub1(self):
        print 'Calling SubTest1:testSub1'
        sub = 3
        self.assertEquals(sub, 3)


class SubTest2(BaseTest):

    def testSub2(self):
        print 'Calling SubTest2:testSub2'
        sub = 4
        self.assertEquals(sub, 4)

del(BaseTest)

if __name__ == '__main__':
    unittest.main()


답변

Matthew Marshall의 대답은 훌륭하지만 각 테스트 사례에서 오류가 발생하기 쉬운 두 클래스에서 상속해야합니다. 대신, 나는 이것을 사용합니다 (python> = 2.7) :

class BaseTest(unittest.TestCase):

    @classmethod
    def setUpClass(cls):
        if cls is BaseTest:
            raise unittest.SkipTest("Skip BaseTest tests, it's a base class")
        super(BaseTest, cls).setUpClass()


답변

당신은 무엇을 달성하려고합니까? 당신이 일반적인 테스트 코드 (주장, 템플릿 테스트 등)이 있다면,로 시작하지 않는 방법에 배치 test그래서 unittest그들을로드되지 않습니다.

import unittest

class CommonTests(unittest.TestCase):
      def common_assertion(self, foo, bar, baz):
          # whatever common code
          self.assertEqual(foo(bar), baz)

class BaseTest(CommonTests):

    def testCommon(self):
        print 'Calling BaseTest:testCommon'
        value = 5
        self.assertEquals(value, 5)

class SubTest1(CommonTests):

    def testSub1(self):
        print 'Calling SubTest1:testSub1'
        sub = 3
        self.assertEquals(sub, 3)

class SubTest2(CommonTests):

    def testSub2(self):
        print 'Calling SubTest2:testSub2'
        sub = 4
        self.assertEquals(sub, 4)

if __name__ == '__main__':
    unittest.main()


답변

매튜의 대답은 내가 2.5 살 때부터 사용해야했던 것입니다. 그러나 2.7부터 건너 뛰려는 모든 테스트 메소드에서 @ unittest.skip () 데코레이터를 사용할 수 있습니다.

http://docs.python.org/library/unittest.html#skipping-tests-and-expected-failures

기본 유형을 확인하려면 자체 건너 뛰기 데코레이터를 구현해야합니다. 이 기능을 전에 사용하지는 않았지만 머리 꼭대기에서 BaseTest를 마커 유형으로 사용하여 건너 뛰기를 조정할 수 있습니다 .

def skipBaseTest(obj):
    if type(obj) is BaseTest:
        return unittest.skip("BaseTest tests skipped")
    return lambda func: func


답변

내가 이것을 해결하려고 생각한 방법은 기본 클래스가 사용되는 경우 테스트 메소드를 숨기는 것입니다. 이렇게하면 테스트를 건너 뛰지 않으므로 많은 테스트보고 도구에서 테스트 결과가 노란색 대신 녹색이 될 수 있습니다.

PyCharm과 같은 ide는 mixin 메소드와 비교할 때 단위 테스트 메소드가 기본 클래스에서 누락되었다고 불평하지 않습니다.

기본 클래스가이 클래스에서 상속되면 setUpClassand tearDownClass메소드 를 대체해야 합니다.

class BaseTest(unittest.TestCase):
    @classmethod
    def setUpClass(cls):
        cls._test_methods = []
        if cls is BaseTest:
            for name in dir(cls):
                if name.startswith('test') and callable(getattr(cls, name)):
                    cls._test_methods.append((name, getattr(cls, name)))
                    setattr(cls, name, lambda self: None)

    @classmethod
    def tearDownClass(cls):
        if cls is BaseTest:
            for name, method in cls._test_methods:
                setattr(cls, name, method)
            cls._test_methods = []