Jak bezpośrednio wyszydzić superklasę z makietą Pythona?

Do testowania używam frameworka python mock (http://www.voidspace.org.uk/python/mock/) i chcę wykpić superklasę i skupić się na testowaniu dodanego zachowania podklas.

(Dla zainteresowanych poszerzyłempymongo.collection.Collection i chcę tylko przetestować moje dodatkowe zachowanie. Nie chcę uruchamiać mongodb jako innego procesu do celów testowych.)

Do tej dyskusjiA jest superklasą iB jest podklasą. Ponadto definiuję bezpośrednie i pośrednie wywołania superklasy, jak pokazano poniżej:

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()
Podejście # 1

Zdefiniuj fikcyjną klasę dlaA nazywaMockA I użyćmock.patch zastąpić go testem w czasie wykonywania. To obsługuje bezpośrednie wywołania superklasy. Następnie manipuluj B .__ base__, aby obsługiwać pośrednie wywołania superklasy. (patrz poniżej)

Pojawia się problem, że muszę pisaćMockA aw niektórych przypadkach (jak w przypadkupymongo.collection.Collection) może to wymagać wiele pracy, aby rozwikłać wszystkie wewnętrzne połączenia, które mają wykpić.

Podejście # 2

Pożądanym podejściem jest jakoś użycie klasy mock.Mock () do obsługi wywołań na makiecie w samą porę, a także zdefiniowania wartości return_value lub side_effect w teście. W ten sposób muszę mniej pracować, unikając definicji MockA.

Problem, który mam, polega na tym, że nie mogę wymyślić, jak zmienić B .__ bazy__, aby instancjamock.Mock () można umieścić jako superklasę (muszę tu jakoś wykonać jakieś bezpośrednie powiązanie). Do tej pory ustaliłem toWspaniały() sprawdza MRO, a następnie wywołuje pierwszą klasę, która definiuje daną metodę. Nie wiem, jak zdobyć superklasę, aby obsłużyć czek i odnieść sukces, jeśli natknie się na próbną klasę. __getattr__ nie jest w tym przypadku używany. Chcę, aby super myśleć, że metoda jest zdefiniowana w tym momencie, a następnie użyć funkcji mock.Mock () jak zwykle.

JakWspaniały() odkryć, jakie atrybuty są zdefiniowane w klasie w sekwencji MRO? I czy jest jakiś sposób, żeby tu wtrącić i jakoś go wykorzystaćmock.Mock () w locie?

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

questionAnswers(2)

yourAnswerToTheQuestion