Clarifying Python TDD Practices with pytest – Am I on the Right Track?
I’m trying to better understand Python TDD (Test-Driven Development) principles while building my project using pytest.
So far, writing tests early has helped me reason about code behavior more pragmatically. However, in my current workflow, all functionality was written before the tests except for 3 class variables. Technically, does this mean I’m not really following TDD?
I’m particularly curious about a few things related to Python TDD:
- Should I be writing full tests for a method before implementing any of its logic?
- Is the goal to ensure all tests pass regardless of test data changes (as long as functionality remains intact)?
- Should the number of tests scale significantly with the complexity/size of the class?
I’ve included my current pytest-based test suite for reference (below).
Code for your reference
import pytest
import os
import sys
path = os.path.dirname(os.path.abspath(__file__))
path = path.replace("\\pytest", "")
sys.path.append(path)
path += "\\pyffi"
sys.path.append(path)
from NifExplorer import NifExplorer
from NifExplorer import NifFormat
@pytest.fixture(autouse=True, scope='session')
def setup_nifExplorer():
    Explorers = []
    explorer = NifExplorer()
    explorer.SetBlockType(NifFormat.NiNode)
    explorer.SetResultPath("\\pytest\\results")
    explorer.SetSearchPath("\\pytest\\nif\\base")
    explorer2 = NifExplorer()
    explorer2.SetBlockType(NifFormat.ATextureRenderData)
    explorer2.SetResultPath("\\pytest\\results")
    explorer2.SetSearchPath("\\pytest\\nif\\base")
    explorer3 = NifExplorer()
    explorer3.SetBlockType("NiNode")
    explorer3.SetResultPath("\\pytest\\testResults")
    explorer3.SetSearchPath("\\pytest\\nif\\base")
    Explorers.append(explorer)
    Explorers.append(explorer2)
    Explorers.append(explorer3)
    return Explorers   
@pytest.mark.usefixtures("setup_nifExplorer")
class TestNifExplorer:
    def NifExlorer_BlockType_Is_Not_None(self, setup_nifExplorer):
        assert setup_nifExplorer.BlockType != None
    def NifExplorer_SearchPath_Is_Not_None(self, setup_nifExplorer):
        assert setup_nifExplorer.SearchPath != None
    def NifExplorer_ResultPath_Is_Not_None(self, setup_nifExlorer):
        assert setup_nifExlorer.ResultPath != None
        
    @pytest.mark.parametrize('funcs', (NifExplorer_SearchPath_Is_Not_None, NifExplorer_ResultPath_Is_Not_None, NifExlorer_BlockType_Is_Not_None))
    def test_NifExplorer_Variables_Equal_Not_None(self, setup_nifExplorer, funcs):
        for obj in setup_nifExplorer:
            funcs(self,obj)
        
    def NifExplorer_ResultPath_Directory_Exists(self, setup_nifExplorer):
        assert os.path.exists(setup_nifExplorer.ResultPath) == True
    def NifExplorer_SearchPath_Directory_Exists(self, setup_nifExplorer):
        assert os.path.exists(setup_nifExplorer.SearchPath) == True
    def NifExplorer_SearchPath_Directory_Contains_No_Forward_Slashes(self, setup_nifExplorer):
        assert setup_nifExplorer.SearchPath.count('/') < 1
    def NifExplorer_ResultPath_Directory_Contains_No_Forward_Slashes(self, setup_nifExplorer):
        assert setup_nifExplorer.ResultPath.count('/') < 1
    @pytest.mark.parametrize('funcs', [NifExplorer_ResultPath_Directory_Exists, NifExplorer_SearchPath_Directory_Exists, NifExplorer_SearchPath_Directory_Contains_No_Forward_Slashes, NifExplorer_ResultPath_Directory_Contains_No_Forward_Slashes])
    def test_NifExplorer_Directories_Exist_And_Paths_Contain_No_Forward_Slashes(self, setup_nifExplorer, funcs):
        for obj in setup_nifExplorer:
            funcs(self,obj)
    def NifExplorer_SearchPath_Contains_Nif_Files_Recursively(self, setup_nifExplorer):
        assert setup_nifExplorer.DirectoryContainsNifRecursively(setup_nifExplorer.SearchPath) == True
    @pytest.mark.parametrize('funcs', [NifExplorer_SearchPath_Contains_Nif_Files_Recursively])
    def test_NifExplorer_SearchPath_Contains_Nif_Files(self, setup_nifExplorer, funcs):
        for obj in setup_nifExplorer:
            funcs(self,obj)
if __name__ == "__main__":
    pytest.main()
Based on this, would you say I’m headed in the right direction with Python TDD, or am I misunderstanding something fundamental?
Would appreciate any feedback from those with more experience in this area!
