Search code examples
djangodjango-testing

django test - how to avoid the ForeignKeyViolation


I am struggling to create tests with django with objects that have foreign keys. The tests run with no errors when run individually, but when running all, i get ForeignKeyViolation in the teardown phase (which I don't understand what it does and can't find any info on it).

When starting the testsuite I am creating a bunch of dummy data like this:

def setUp(self) -> None:
    create_bulk_users(5)
    create_categories()
    create_tags()
    create_technologies()
    self.tags = Tag.objects.all()
    self.categories = Category.objects.all()
    self.technologies = Technology.objects.all()

The problems I need help figuring out are:

  1. What exactly the teardown phase does? Are there any detailed docs on it?
  2. How should I structure my tests so to avoid the ForeignKeyViolation issue?

Solution

  • What exactly the teardown phase does? Are there any detailed docs on it?

    I couldn't find any detailed docs about it. All I find out was by reading the actual code. Teardown cancels any operations done to the DB during the tests.

    The way TestCases work (broadly) is this:
    
    1. SetUp method runs **before** every test
    2. individual test method is run
    3. TearDown method runs **after** every test
    4. Test database is flushed
    

    How should I structure my tests so to avoid the ForeignKeyViolation issue?

    My mistake was that I was importing a function for creating dummy data. The imported module was running a function to populate some primary data. The problem was that was not rerun each within the setUp method because it would run just one, when importing the file.

    # imported module
    
    # will delete all tags after running first test but
    # the reference to the old tags will persist
    
    tags = FakeTags.create_bulk();
    
    def create_bulk_articles():
        article = FakeArticle.create()
        article.tags.add(tags)
    

    I fixed it by just using the trouble function inside the imported function.

    # imported module
    
    # tags are created each time before running the tests
    
    def create_bulk_articles():
        tags = FakeTags.create_bulk();
        article = FakeArticle.create()
        article.tags.add(tags)