Как напрямую смоделировать суперкласс с помощью Python mock?

Я использую фреймворк Python для тестирования (http://www.voidspace.org.uk/python/mock/). и я хочу смоделировать суперкласс и сосредоточиться на тестировании добавленного поведения подклассов.

(Для тех, кто заинтересован, я расширил pymongo.collection.Collection и хочу только протестировать добавленное поведение. Я не хочу запускать mongodb как еще один процесс для целей тестирования.)

Для этого обсуждения A является суперклассом, а B — подклассом. Кроме того, я определяю прямые и косвенные вызовы суперкласса, как показано ниже :

class A(object):
    def method(self):
       ...

    def another_method(self):
       ...

class B(A):
    def direct_superclass_call(self):
       ...
        A.method(self)

    def indirect_superclass_call(self):
       ...
        super(A, self).another_method()

. Подход #1

Определите фиктивный класс для A с именем MockA и используйте mock.patch , чтобы заменить его для теста во время выполнения. Это обрабатывает прямые вызовы суперкласса. Затем манипулируйте базами B. ____для обработки косвенных вызовов суперкласса. (см. ниже)

Возникающая проблема заключается в том, что я должен написать MockA и в некоторых случаях (, как в случае с pymongo.collection.Collection)это может потребовать много работы, чтобы разгадать все внутренние вызовы для имитации.

Подход #2

Желаемый подход состоит в том, чтобы каким-то образом использовать класс mock.Mock ()для своевременной обработки вызовов макета, а также определенного возвращаемого _значения или побочного _эффекта на месте в тесте. Таким образом, мне приходится делать меньше работы, избегая определения MockA.

Проблема, с которой я сталкиваюсь, заключается в том, что я не могу понять, как изменить B. __bases __, чтобы экземпляр mock.Mock()может быть реализован как суперкласс (Мне нужно как-то сделать прямое связывание здесь ). До сих пор я определил,что супер()проверяет MRO, а затем вызывает первый класс, определяющий рассматриваемый метод. Я не могу понять, как заставить суперкласс обработать проверку и преуспеть, если он встретит фиктивный класс. __getattr __в данном случае не используется. Я хочу, чтобы super думал, что метод определен в этот момент, а затем, как обычно, использовал функциональность mock.Mock ().

Как работает супер()узнать, какие атрибуты определены в классе в последовательности MRO? И есть ли способ для меня вставить здесь и каким-то образом заставить его использовать mock.Mock()на лету?

import mock

class A(object):
    def __init__(self, value):
        self.value = value      

    def get_value_direct(self):
        return self.value

    def get_value_indirect(self):
        return self.value   

class B(A):
    def __init__(self, value):
        A.__init__(self, value)

    def get_value_direct(self):
        return A.get_value_direct(self)

    def get_value_indirect(self):
        return super(B, self).get_value_indirect()


# approach 1 - use a defined MockA
class MockA(object):
    def __init__(self, value):
        pass

    def get_value_direct(self):
        return 0

    def get_value_indirect(self):
        return 0

B.__bases__ = (MockA, )  # - mock superclass 
with mock.patch('__main__.A', MockA):  
    b2 = B(7)
    print '\nApproach 1'
    print 'expected result = 0'
    print 'direct =', b2.get_value_direct()
    print 'indirect =', b2.get_value_indirect()
B.__bases__ = (A, )  # - original superclass 


# approach 2 - use mock module to mock out superclass

# what does XXX need to be below to use mock.Mock()?
#B.__bases__ = (XXX, )
with mock.patch('__main__.A') as mymock:  
    b3 = B(7)
    mymock.get_value_direct.return_value = 0
    mymock.get_value_indirect.return_value = 0
    print '\nApproach 2'
    print 'expected result = 0'
    print 'direct =', b3.get_value_direct()
    print 'indirect =', b3.get_value_indirect() # FAILS HERE as the old superclass is called
#B.__bases__ = (A, )  # - original superclass
18
задан Rocketman 7 December 2012 в 20:51
поделиться