6

I'm pretty new to Python and I'm setting up a little game and I want to test it. Currently, I'm generating an array of objects (Rock, Paper, Scissors) and each of them inherit from a Roll object:

def build_the_three_rolls():
  return [Rock(), Paper(), Scissors()]

This is my test with py.test:

def test_building_rolls():
  assert len(build_the_three_rolls()) == 3
  assert isinstance(build_the_three_rolls()[0], Rock)
  assert isinstance(build_the_three_rolls()[1], Paper)
  assert isinstance(build_the_three_rolls()[2], Scissors)

but when I run it, I'm getting the following error:

>       assert isinstance(build_the_three_rolls()[1], Paper)
E       assert False
E        +  where False = isinstance(<roll.Paper object at 0x110ab42e8>, Paper)

I don't understand why it fails

Thanks!

UPDATE:

Here's the definition of Roll and its child classes:

class Roll:
def __init__(self, name, defeated_by_self, defeat_self):
    self.name = name
    self.defeated_by_self = defeated_by_self
    self.defeat_self = defeat_self


class Rock(Roll):
    def __init__(self):
        defeated_by_self = {}
        defeated_by_self["Scissors"] = "Scissors"
        defeat_self = {}
        defeat_self["Paper"] = "Paper"
        super().__init__("Rock", defeated_by_self, defeat_self)


class Paper(Roll):
    def __init__(self):
        defeated_by_self = {}
        defeated_by_self["Rock"] = "Rock"
        defeat_self = {}
        defeat_self["Scissors"] = "Scissors"
        super().__init__("Paper", defeated_by_self, defeat_self)


class Scissors(Roll):
    def __init__(self):
        defeated_by_self = {}
        defeated_by_self["Paper"] = "Paper"
        defeat_self = {}
        defeat_self["Rock"] = "Rock"
        super().__init__("Scissors", defeated_by_self, defeat_self)
noloman
  • 11,411
  • 20
  • 82
  • 129
  • 4
    We're gonna need a [mcve]. – Aran-Fey Apr 05 '18 at 16:34
  • In general, if you use `isinstance` without a really-really good reason, your design is wrong. In your case, I'd say what you want is an [`enum`](https://docs.python.org/3/library/enum.html). – 9000 Apr 05 '18 at 16:38
  • 1
    @9000 That's complete nonsense. This is python, not Java. It's especially wrong for testing purposes. – FHTMitchell Apr 05 '18 at 16:44
  • @FHTMitchell: It applies to Python as much as it does to Java, or basically to any OO-ish language. Your objects should know what to do; you should not care about their specific classes as long as they match some base class / interface (see [LSP](https://en.wikipedia.org/wiki/Liskov_substitution_principle)). For testing I can see how `isinstance` can be useful, but, _to my mind, in this particular case,_ it's likely not. – 9000 Apr 05 '18 at 16:48
  • @9000 And how are you checking for these base classes? `isinstance`, right? For the record `isinstance` is used 400 times in the stdlib. https://github.com/search?utf8=%E2%9C%93&q=isinstance+repo%3Apython%2Fcpython+path%3A%2FLib+language%3APython&type=Code&ref=advsearch&l=Python&l= – FHTMitchell Apr 05 '18 at 16:49
  • On topic: `isinstance(, Paper)` may be false if `Paper` is _not_ the same thing as `roll.Paper`. Do you have anything in your test code that could shadow the definition of `Paper`? – 9000 Apr 05 '18 at 17:01
  • Please include a definition of Paper class. – Belerafon Apr 06 '18 at 15:39
  • 1
    Thanks a lot for the comments guys! I understand that testing with `isinstance` is not the most appropriate, but I'm just trying to understand why python or pytest tells me that object is not an instance of Paper, or Rock or Scissors (because it happens with each one) – noloman Apr 08 '18 at 17:13

1 Answers1

1

I hit a similar issue and ultimately discovered that in my case it had to do with a relative import path issue. When I investigated MySubClass.__class__ from ipython run in the directory with MyClass's module it was different than the same thing when pytest was run on the tests folder. Example below:

Directory structure:

└── project
    ├── __init__.py
    ├── src
    │   ├── __init__.py
    │   ├── my_module.py
    └── tests
        ├── __init__.py
        └── test_my_module.py

my_module.py:

class MyClass:
    def __init__(self, param1):
        self.param1 = param1

class MySubClass(MyClass):
    def __init__(self, param1):
        super().__init__(param1)

test_my_module.py:

def test_my_sub_class():
    pkl_instance = # loaded from a pkl file saved from ipython
    test_instance = MySubClass(param1="This was instantiated in 
    test_my_module.py")

    # assert isinstance(pkl_instance, test_instance) fails
    print(pkl_instance.__class__)   # <class 'my_module.MySubClass'>
    print(test_instance.__class__)  # <class 'project.src.my_module.MySubClass'>
ZaxR
  • 4,896
  • 4
  • 23
  • 42