Python, importing modules for testing

Question:

I am having a very hard time trying to set up a simple test.

My project structure is as follows:

project:
   models:
      __init__.py
      user.py
      constants.py
      test:
         test.py

I want to test user.py py running test.py.

user.py

from sqlalchemy import Column, Integer, String, Text
from sqlalchemy.orm import relationship
from .models.constants import *
from .models import Base

class User(Base):
    __tablename__ = 'users'

    uid = Column(Integer, primary_key=True, autoincrement=True)
    name = Column(String, nullable=False)
    email = Column(String, nullable=False)
    picPath = Column(String, unique=True)
    description = Column(Text)

    def __repr__(self):
        return "<User(uid=%s, name=%s)>" %(self.uid, self.name)

test.py

from ..user import User, Group

def _TestUser():
    TEST_DB_URI = "postgresql://project:password@localhost:5432/projectdbtest"
    SessionMaker = sessionmaker()
    engine = create_engine(TEST_DB_URI)
    SessionMaker.configure(bind=engine)

    session = SessionMaker()
    user = User("test subject", "[email protected]", "~/testsubject.jpg", "I am a test subject")
    session.add(user)
    session.commit()

However, I am getting the following error when I run python3 -m test.py:

SystemError: Parent module ” not loaded, cannot perform relative import

I think I might have to add the modules package to the python path?

Asked By: mrQWERTY

||

Answers:

Here is few things, which have simplified my testing and which work for me very well.

Always test from project root

Initially I was assuming, my test cases shall be usable from whatever directory.

In fact, there is no reason to make test cases flexible in this way and decision to run all tests from project root only strongly simplify the solution.

It might be obvious to many programmers, but to me it was big step towards simplified testing.

Keep test directory separate from package code

Mixing production code with test code seems logical, but soon becomes messy.

Finally I have decided to use separate tests (in plural) directory in the project and it works very well for me.

Advantages are:

  • tests are “close” to pick (see next part related to py.test) and use manually or from other tools like tox.
  • no need to hunt for test directories somewhere in the package directories, they are simply living in separate place
  • feel safe to experiment with tests – because you are out from main code.

Note: try to use always name tests, do not use test. Keeping this simple rule will simplify your work as you will always know the real name of your test directory.

Use pytest testing framework

There are multiple testing frameworks (unittest, nose, nose2, pytest) and in fact all provide the basics you need.

Anyway, I have found pytest (with py.test command) being real fun to use for couple of reasons:

  • can run most tests written in other framework (unittest, nose…)
  • very easy to create first test function.
  • test functions can be kept very simple and excellent fixtures will inject needed values into it. Once you try it, you will not use other methods.
  • allows naturally extending the test suite
  • very good to start prototyping your code and evolve to production one:
    • start in test function
    • move out of test function to independent function in the same test file
    • move to external module (and most of your testing code does not change)

Avoid using __init__.py in test suite dir

See Choosing a test layout/import rules for explanation and follow the advice to avoid using __init__.py.

In short, things will be simpler.

Note, that other approaches will work too and are not wrong – I just wanted to share what works very well for me.

Answered By: Jan Vlcinsky

I faced the same problem recently.

Adding the following __init__.py file in the test folder solved the issue for me :

import os
import sys
PROJECT_PATH = os.getcwd()
sys.path.append(PROJECT_PATH)
Answered By: mahmoud mehdi
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.