Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Execute some code before Pytest runs

Tags:

python

pytest

I'm using Pytest to test my code and I'm running into a little, but an infuriating issue.

One of the first things my program does is checking if there are any setting files available. If there aren't any it throws an error and calls exit(). This works well during normal runtime but messes with Pytest.

The solution I came up with is to simply create a temporary settings file for the duration of the tests, by copying the template settings file. I've already written and successfully tested the code to achieve that.

The problem I'm running into is that I can't find a Pytest hook that truly fires before everything else. This results in the program throwing the error before Pytest tries to create a temporary settings file. Which results in Pytest failing before it can perform any tests.

Does anyone know of a way to fire a function before Pytest does or loads anything? Preferably within Pytest itself.

Some code context:

Throwing the error and exit

This snippet runs on the import of the settings module.

if len(cycles) == 0:
    log.error("No setting files found. Please create a file " +
              "in the `settings` folder using the Template.py.")
    exit()

Creating the temporary settings file

This code should be the very first thing Pytest runs.

def pytest_sessionstart(session):
    """ Create a test settings file """
    folderPath = os.path.dirname(os.path.abspath(__file__))
    folderPath = os.path.split(folderPath)[0] + "/settings"

    srcfile = folderPath + '/Template.py'
    dstfile = folderPath + '/test.py'

    shutil.copy(srcfile, dstfile)

Removing the temporary settings file

This code should be one of the last things Pytest runs.

def pytest_sessionfinish(session, exitstatus):
    """ Delete the test settings file """
    folderPath = os.path.dirname(os.path.abspath(__file__))
    folderPath = os.path.split(folderPath)[0] + "/settings"

    os.remove(folderPath + "/test.py")

Pytest output

With the call to exit() disabled, so you can see the execution order.

Lakitna$ pytest -v -s
 No setting files found. Please create a file in the `settings` folder using the Template.py. 
TEMPORARY SETTINGS FILE CREATED
========================= test session starts ==========================
platform darwin -- Python 3.6.4, pytest-3.3.1, py-1.5.2, pluggy-0.6.0 -- /usr/local/opt/python3/bin/python3.6
cachedir: .cache
rootdir: /Users/lakitna/Documents/Github/Onaeri-tradfri/Onaeri, inifile:
collected 24 items
like image 532
Lakitna Avatar asked Jan 05 '18 12:01

Lakitna


2 Answers

Add conftest.py to your project with below code and add your code to method pytest_configure

def pytest_configure(config):
    pass # your code goes here

# other config
like image 60
Nam G VU Avatar answered Oct 01 '22 06:10

Nam G VU


I've managed to find a solution.

After some additional research, I found out that Pytest preloads all modules. This means that you can never run code before a module import unless you can find a hook before the collection phase. There is no such hook as far as I know. I really wanted to make this work within Pytest, but it seems to be impossible.

Instead, I created a __main__.py file in my test folder with the following content:

import pytest
import os
import shutil

"""
Create a setting file for the test procedure
"""
folderPath = os.path.dirname(os.path.abspath(__file__))
folderPath = os.path.split(folderPath)[0] + "/settings"

srcfile = folderPath + '/Template.py'
dstfile = folderPath + '/test.py'

shutil.copy(srcfile, dstfile)

"""
Actually run pytest
"""
pytest.main()

"""
Remove the test settings file
"""
os.remove(dstfile)

This code creates a temporary settings file, starts Pytest, and then removes the temporary file again.

I can now run the test procedure as follows:

$ python3 test

Pytest flags still work as normal. For example, if you want more verbose output you can do the following:

$ python3 test -v
like image 33
Lakitna Avatar answered Oct 01 '22 07:10

Lakitna