Trying to import from class for pytest

Question:

This feels like a silly question, but I am trying to import a class to do testing with pytest and it does not seem to want to work. I am not sure why it is still greyed out when I look at it in pycharm.

Here is my code

from classes import *

class Test:
    def setup_method(self):
        self.tv1 = power(True)

    def teardown_method(self):
        del self.tv1

    def test_power(self):
        assert power(True) is True
        assert power(False) is False

Greyed out in pycharm

Here is part of the class file:

classes.py is the file name.

class Television:
    """
    A class building functions for a remote control object

    Global variables for each function use
    :param MIN_CHANNEL: Channel cannot decrease beyond this
    :param MAX_CHANNEL: Channel cannot increase beyond this
    :param MIN_VOLUME: Volume cannot decrease beyond this
    :param MAX_VOLUME: Volume cannot increase beyond this
    """

    MIN_CHANNEL = 0
    MAX_CHANNEL = 3

    MIN_VOLUME = 0
    MAX_VOLUME = 2

    def __init__(self) -> None:
        """
        Constructor to create initial state of television object
        :param channel: Value to store channel number
        :param volume: Value to store volume level
        :param status: Value to store if TV is on or off
        """

        self.__channel = Television.MIN_CHANNEL                # - Create a private variable to store the TV channel. It should be set to the minimum TV channel by default.
        self.__volume = Television.MIN_VOLUME                  # - Create a private variable to store the TV volume. It should be set to the minimum TV volume by default.
        self.__status = False                           # - Create a private variable to store the TV status. The TV should start when it is off.


    def power(self) -> None:
        """
        Method to change status of the TV
        :return: On or Off status of TV
        """

        if self.__status == False:                      # - This method should be used to turn the TV on/off.
            self.__status = True                       # - If called on a TV object that is off, the TV object should be turned on.
        else:
            self.__status = False                       # - If called on a TV object that is on, the TV object should be turned off.
Asked By: DoomDragoon

||

Answers:

There are a few things going on with this example code so I’ll try to address some of them here:

Object instantiation

It looks like you wrote the power function as a method of the Television class, hence why it is not available to use directly. Thus instead of this:

from classes import *
power()

You will need to instantiate the object first and then call the method on the instantiated object:

tv = Television()
tv.power()

The power state in this example is only maintained in the instance of Television assigned to the tv variable above.

Rewriting the tests

Your power method toggles the power but you do not provide a way to access the internal state for testing (it’s not good practice to access the attribute prefixed with an _ or __). You could have that method return the new state, or provide a property method that returns the state from the internal variable. For the example here I will choose the former:

    # Note we change the return type to bool
    def power(self) -> bool:
        # your power function
        # Add this return statement
        return self.__status

Now we don’t need to explicitly delete objects in Python (although you can), because the garbage collector will handle the object destruction. So we can simply write our test as:

    def test_power(self):
        tv = Television()
        assert tv.power()
        assert not tv.power()

Simplifying toggle method

To toggle the value you just want to negate the boolean:

self.__status = not self.__status

Private class members

While Python doesn’t enforce public/private attributes on objects by default, a single underscore is the PEP8 (a common style guide) way of showing that a variable is "internal".

_single_leading_underscore: weak “internal use” indicator. E.g. from M import * does not import objects whose names start with an underscore.

Specifying a sources root

PyCharm also has to know which directory (or directories) in your project it should use to resolve imports. To tell PyCharm about this you can mark the directory containing the classes.py and test_classes.py file as a "Sources Root". Right click (or Ctrl-Click on Mac) the directory in the file tree on the left and then choose Mark Directory as > Sources Root. You may not need to do this, depending on how you set up your PyCharm project.

Answered By: bms
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.