2

Let's say I have a function that is documented to take a collections.Sequence ABC. How do I test the code within this function against the ABC interface? Can I write a unit test (or tests) confirming that my code only calls methods defined by this ABC and not, say, a method defined by list or some other concrete implementation of collections.Sequence? Or is there some other tool or method to verify this?

detly
  • 29,332
  • 18
  • 93
  • 152

2 Answers2

1

Simply test the function by passing an instance of a class that only implements those methods. If you need to, you can subclass a built-in type such as list and override its __getattribute__ method, like this:

class TestSequence(list):
    def __getattribute__(self, name):
        if name not in collections.Sequence.__abstractmethods__:
            assert(False) # or however you'd like the test to fail
        return object.__getattribute__(self, name)
jangler
  • 949
  • 6
  • 7
  • "an instance of a class that only implements those methods" — this is the core of what I'm asking, I think: is there an easier way to obtain such a thing? Your method works, but duplicates information that is already in the ABC. Thus, there's a risk of getting out of sync, making another mistake, etc. (Also, if someone were to do this, they might be better off using a mock object or similar... depending on the test.) – detly May 29 '15 at 03:13
  • Would using `if name not in Sequence.__abstractmethods__` solve your problem? – jangler May 29 '15 at 03:25
0

Implement the ABC directly yourself, with methods as trivial or complex as needed by the code:

import collections

class TestSequence(collections.Sequence):

    def __init__(self):
        pass

    def __len__(self):
        return 3

    def __getitem__(self, index):
        return index

If you make a mistake and omit abstract method implementations, your code will produce an error:

TypeError: Can't instantiate abstract class TestSequence with abstract methods __getitem__

If your code under test calls a method not defined by the ABC, you will see the usual no attribute error:

AttributeError: 'TestSequence' object has no attribute 'pop'
detly
  • 29,332
  • 18
  • 93
  • 152