programing

기본 및 하위 클래스를 사용한 Python 장치 테스트

javajsp 2023. 6. 28. 21:20

기본 및 하위 클래스를 사용한 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가지 테스트만 실행했으면 합니다.Python unittest는 자체적으로 원본 BaseTest를 실행하고 있는 것 같은데, 그런 일이 일어나지 않도록 장치가 필요합니다.

다중 상속을 사용하지 마십시오. 나중에 물어뜯을 수 있습니다.

대신 기본 클래스를 별도의 모듈로 이동하거나 빈 클래스로 묶으면 됩니다.

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

공통 테스트가 있는 클래스 자체가 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()

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

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의 답변은 훌륭하지만, 각 테스트 사례에서 오류가 발생하기 쉬운 두 개의 클래스를 상속해야 합니다.대신 다음을 사용합니다(예:>=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__ = False클래스에 BaseTest 클에추가경우합추니다를 .__test__ = True파생 클래스에서 테스트를 실행할 수 있습니다.

import unittest

class BaseTest(unittest.TestCase):
    __test__ = False

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

class SubTest1(BaseTest):
    __test__ = True

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


class SubTest2(BaseTest):
    __test__ = True

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

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

당신은 무엇을 성취하려고 노력하고 있습니까? 코드 시험가 붙지 으로 시험 코드를 작성합니다.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 이후에는 건너뛰고 싶은 모든 테스트 방법에 the @unittest.sk iptx 데코레이터를 사용할 수 있습니다.

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

기본 유형을 확인하려면 고유한 건너뛰기 장식기를 구현해야 합니다.이전에 이 기능을 사용해 본 적은 없지만, 기본 테스트를 마커 유형으로 사용하여 건너뛰기 조건을 지정할 수 있습니다.

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

이 문제를 해결하기 위해 생각한 방법은 기본 클래스를 사용할 경우 테스트 방법을 숨기는 것입니다.이렇게 하면 테스트를 건너뛸 수 없으므로 많은 테스트 보고 도구에서 테스트 결과가 노란색이 아닌 녹색이 될 수 있습니다.

믹스인 방식과 비교했을 때, 아이디어는 PyCharm이 기본 클래스에서 단위 테스트 방법이 누락되었다고 불평하지 않을 것입니다.

기본 클래스가 이 클래스에서 상속되는 경우 다음을 재정의해야 합니다.setUpClass그리고.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 = []

다른 옵션은 실행하지 않는 것입니다.

unittest.main()

대신에 당신은 사용할 수 있습니다.

suite = unittest.TestLoader().loadTestsFromTestCase(TestClass)
unittest.TextTestRunner(verbosity=2).run(suite)

그래서 당신은 수업에서 테스트만 실행합니다.TestClass

다음은 문서화된 단위 테스트 기능만 사용하고 테스트 결과에 "건너뛰기" 상태가 되는 것을 방지하는 솔루션입니다.

class BaseTest(unittest.TestCase):

    def __init__(self, methodName='runTest'):
        if self.__class__ is BaseTest:
            # don't run these tests in the abstract base implementation
            methodName = 'runNoTestsInBaseClass'
        super().__init__(methodName)

    def runNoTestsInBaseClass(self):
        pass

    def testCommon(self):
        # everything else as in the original question

작동 방식: 설명서에 따르면, "TestCase의 각 인스턴스는 methodName이라는 이름의 메서드인 단일 기본 메서드를 실행합니다."기본 "runTests"는 클래스의 모든 test* 메서드를 실행합니다. 이것이 TestCase 인스턴스의 일반적인 작동 방식입니다.그러나 추상 기본 클래스 자체에서 실행할 때는 아무 것도 하지 않는 메서드로 해당 동작을 재정의할 수 있습니다.

부작용으로는 테스트 횟수가 1회 증가한다는 것입니다. runNoTestsInBaseClass "test"는 BaseClass에서 실행될 때 성공적인 테스트로 계산됩니다.

(이 기능은 Python 2.7에서도 사용할 수 있습니다.그냥 바꾸기super()로.super(BaseTest, self).)

testCommon 메서드의 이름을 다른 메서드로 변경합니다.Unittest(일반적으로)는 'test'가 포함되지 않은 모든 항목을 건너뜁니다.

빠르고 간단하게

  import unittest

  class BaseTest(unittest.TestCase):

   def methodCommon(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()`

저는 @Vladim P.(https://stackoverflow.com/a/25695512/2451329) 과 거의 동일하게 만들었지만 약간 수정했습니다.

import unittest2


from some_module import func1, func2


def make_base_class(func):

    class Base(unittest2.TestCase):

        def test_common1(self):
            print("in test_common1")
            self.assertTrue(func())

        def test_common2(self):
            print("in test_common1")
            self.assertFalse(func(42))

    return Base



class A(make_base_class(func1)):
    pass


class B(make_base_class(func2)):

    def test_func2_with_no_arg_return_bar(self):
        self.assertEqual("bar", func2())

자, 시작합니다.

Python 3.2 이후에는 모듈에 test_loader 함수를 추가하여 테스트 검색 메커니즘에 의해 발견되는 테스트(있는 경우)를 제어할 수 있습니다.

예를 들어, 다음은 원본 포스터의 내용만 로드합니다.SubTest1그리고.SubTest2테스트 사례, 무시Base:

def load_tests(loader, standard_tests, pattern):
    suite = TestSuite()
    suite.addTests([SubTest1, SubTest2])
    return suite

그것을 반복하는 것은 가능해야 합니다.standard_tests(a)TestSuite기본 로더에서 찾은 테스트 포함) 및 copy all butBase로.suite대신, 그러나 중첩된 특성TestSuite.__iter__훨씬 더 복잡하게 만듭니다.

이것은 일종의 오래된 스레드이지만 저는 오늘 이 문제를 접했고 그것을 위한 저만의 해킹을 생각했습니다.기본 클래스를 통해 액세스할 때 함수 값을 없음으로 만드는 장식기를 사용합니다.기본 클래스에 테스트가 없으면 실행되지 않으므로 설정 및 설정 클래스에 대해 걱정할 필요가 없습니다.

import types
import unittest


class FunctionValueOverride(object):
    def __init__(self, cls, default, override=None):
        self.cls = cls
        self.default = default
        self.override = override

    def __get__(self, obj, klass):
        if klass == self.cls:
            return self.override
        else:
            if obj:
                return types.MethodType(self.default, obj)
            else:
                return self.default


def fixture(cls):
    for t in vars(cls):
        if not callable(getattr(cls, t)) or t[:4] != "test":
            continue
        setattr(cls, t, FunctionValueOverride(cls, getattr(cls, t)))
    return cls


@fixture
class BaseTest(unittest.TestCase):
    def testCommon(self):
        print('Calling BaseTest:testCommon')
        value = 5
        self.assertEqual(value, 5)


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


class SubTest2(BaseTest):

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

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

기본 테스트 메서드 이름을 setUp:

class BaseTest(unittest.TestCase):
    def setUp(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)

출력:

0.000초 동안 두 번의 테스트 실행

호출 베이스 테스트:testCommon 호출
SubTest1:testSub1 호출
:testCommonCalling
파일 2:testSub2

설명서에서 다음을 참조하십시오.

테스트 사례.설정()
테스트 픽스처를 준비하기 위해 호출되는 메서드입니다.이는 테스트 방법을 호출하기 직전에 호출됩니다. 이 방법으로 발생한 예외는 테스트 실패가 아닌 오류로 간주됩니다.기본 구현에서는 아무런 작업도 수행하지 않습니다.

언급URL : https://stackoverflow.com/questions/1323455/python-unit-test-with-base-and-sub-class