Python, importing modules for testing
Asked Answered
F

2

24

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?

Flageolet answered 25/2, 2016 at 19:39 Comment(1)
Take a look hereClaudineclaudio
H
31

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.

Haematocele answered 25/2, 2016 at 20:11 Comment(1)
This is a very contentious point: "Keep test directory separate from package code"Greenhead
T
3

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)
Tjader answered 23/8, 2022 at 12:53 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.