Home > Back-end >  pytest fixtures: testing pandas dataframe
pytest fixtures: testing pandas dataframe

Time:12-29

I have some scripts in package directory and some tests in tests directory, along with a CSV file containing a dataframe that i want to use for testing purposes.

main_directory/
  |
  |- package/
  |   |- foo.py
  |   |- bar.py
  | 
  |- tests/
      |- conftest.py
      |- test1.py
      |- test.csv

I am using pytest and i have defined a conftest.py that contains a fixture that i want to use for the whole test session, that should return a pandas test dataframe imported from a csv file, as in the following:

#conftest.py

import pytest
from pandas import read_csv

path="test.csv"

@pytest.fixture(scope="session")
def test_data():
    return read_csv(path)

I have been trying to use the fixture to return the test dataframe for the test_functions.

The original test functions were a bit more complex, calling pandas groupby on the object returned by the fixture. I kept on getting the error 'TestStrataFrame' object has no attribute 'groupby' so i simplified the test to the test below and, as I was still getting errors, I realized that i am probably missing something.

My test is the following:

#test1.py
import unittest
import pytest

class TestStrataFrame(unittest.TestCase):

    def test_fixture(test_data):
        assert isinstance(test_data,pd.DataFrame) is True

The above test_fixture returns:

=============================================== FAILURES ================================================
_____________________________________ TestStrataFrame.test_fixture ______________________________________

test_data = <tests.test_data.TestStrataFrame testMethod=test_fixture>

    def test_fixture(test_data):
        ciao=test_data
>       assert isinstance(ciao,pd.DataFrame) is True
E       AssertionError: assert False is True
E           where False = isinstance(<tests.test_data.TestStrataFrame testMethod=test_fixture>, <class 'pandas.core.frame.DataFrame'>)
E             where <class 'pandas.core.frame.DataFrame'> = pd.DataFrame

tests/test_data.py:23: AssertionError
=========================================== warnings summary ============================================
../../../../../opt/miniconda3/envs/geo/lib/python3.7/importlib/_bootstrap.py:219
  /opt/miniconda3/envs/geo/lib/python3.7/importlib/_bootstrap.py:219: RuntimeWarning: numpy.ufunc size changed, may indicate binary incompatibility. Expected 192 from C header, got 216 from PyObject
    return f(*args, **kwds)

-- Docs: https://docs.pytest.org/en/stable/warnings.html
======================================== short test summary info ========================================
FAILED tests/test_data.py::TestStrataFrame::test_fixture - AssertionError: assert False is True
================================ 1 failed, 4 passed, 1 warning in 12.82s ================================

How can i do this correctly?

PS : At the moment i would not focus on the RuntimeWarning. I am getting since after I have started trying to solve this issue, but i am quite sure the tests were failing even before I got that warning - so they are probably unrelated. I reinstalled the environment and the warning persists, hopefully might go away with solving the issue...

CodePudding user response:

The error is coming as test_data is not been passed to test_fixture method. for example below are two ways you can tweak your Class and its method.

import unittest
import pytest
import pandas as pd

class TestStrataFrame(unittest.TestCase):
    test_data=pd.DataFrame()
    def test_fixture(self):
        test_data=pd.DataFrame()
        assert isinstance(test_data,pd.DataFrame) is True
    def test_fixture_1(self):
        assert isinstance(TestStrataFrame.test_data,pd.DataFrame) is True

and run from terminal : pytest test_sample.py

CodePudding user response:

This is the expected behavior if you take note of this page here. That page clearly states:

The following pytest features do not work, and probably never will due to different design philosophies:

 1. Fixtures (except for autouse fixtures, see below);
 2. Parametrization;
 3. Custom hooks;

You can modify your code to the following to work.

# conftest.py
from pathlib import Path
import pytest
from pandas import read_csv

CWD = Path(__file__).resolve()
FIN = CWD.parent / "test.csv"

@pytest.fixture(scope="class")
def test_data(request):
    request.cls.test_data = read_csv(FIN)


# test_file.py
import unittest
import pytest
import pandas as pd

@pytest.mark.usefixtures("test_data")
class TestStrataFrame(unittest.TestCase):
    def test_fixture(self):
        assert hasattr(self, "test_data")
        assert isinstance(self.test_data, pd.DataFrame)

==>pytest tests/
============================= test session starts ==============================
platform darwin -- Python 3.9.1, pytest-6.2.2, py-1.10.0, pluggy-0.13.1
rootdir: /Users/***/Desktop/scripts/stackoverflow
collected 1 item                                                               

tests/test_file.py .                                                     [100%]

============================== 1 passed in 0.03s ===============================

You can see more about mixing fixtures with the unittest framework here.

  • Related