Upgrade to Pro — share decks privately, control downloads, hide ads and more …

factory_boy: testing like a pro. DjangoCon US 2022

factory_boy: testing like a pro. DjangoCon US 2022

Camila Maia

October 13, 2022
Tweet

More Decks by Camila Maia

Other Decks in Technology

Transcript

  1. @cmaiacd
    factory_boy
    DjangoCon US - Oct 2022
    Camila Maia
    testing like a pro

    View Slide

  2. @cmaiacd
    You can find this presentation at:
    speakerdeck.com/cmaiacd

    View Slide

  3. @cmaiacd
    Who am I?

    View Slide

  4. @cmaiacd
    Brazilian living in Berlin
    Bachelor of Computer Information System
    Coding since 2010 👵
    Python 🐍 and Ruby 💎
    Open Source and Community ❤
    Conferences
    Backend Developer @ SoundCloud

    View Slide

  5. @cmaiacd
    Creator of ScanAPI

    View Slide

  6. @cmaiacd
    First GitHub profile to be accepted for
    the GitHub Sponsors program in Brazil
    󰎙
    Quem sou eu?

    View Slide

  7. @cmaiacd
    factory_boy: what is it?

    View Slide

  8. @cmaiacd
    ● It is a fixtures replacement
    ● Based on factory_bot (Thoughtbot)
    ● First version: Django only
    ● Nowadays: framework-independent
    ● Unittest, Pytest...

    View Slide

  9. @cmaiacd
    For complex objects:
    ❌ Fixtures: static, hard to maintain
    ✅ Factories: easy-to-use

    View Slide

  10. @cmaiacd
    ❌ Fixtures:
    exhaustive test setup with every possible combination
    of corner cases
    ✅ Factories:
    objects customized for the current test, while only
    declaring the test-specific fields

    View Slide

  11. @cmaiacd
    It offers many tools that help with the creation of the tests:
    ● Sequence
    ● Faker
    ● Fuzzy attributes
    ● LazyFunction
    ● LazyAttribute
    ● Inheritance
    ● Params
    ● Traits
    ● Strategies
    ● RelatedFactory/SubFactory

    View Slide

  12. @cmaiacd
    Demo App

    View Slide

  13. @cmaiacd
    Polls

    View Slide

  14. @cmaiacd
    Poll

    View Slide

  15. @cmaiacd
    Results

    View Slide

  16. @cmaiacd
    Model - Poll
    Poll Question Choice
    n:1
    pub_date : DateTimeField
    premium : BooleanField
    author : CharField
    question_text : CharField
    language : CharField
    choice_text : CharField
    votes : IntegerField
    1:1

    View Slide

  17. @cmaiacd
    Create Question - Admin

    View Slide

  18. @cmaiacd
    Create Question - Admin

    View Slide

  19. @cmaiacd
    Questions - Admin

    View Slide

  20. @cmaiacd
    Model - Poll

    View Slide

  21. @cmaiacd
    Model - Poll

    View Slide

  22. @cmaiacd
    Model - Question

    View Slide

  23. @cmaiacd
    Model - Choice

    View Slide

  24. @cmaiacd
    Best Practices

    View Slide

  25. @cmaiacd
    ● +3 years
    ● Django Monolith
    ● +230 tables
    ● +2200 relevant files
    ● +75k relevant lines
    My experience

    View Slide

  26. @cmaiacd
    Bad factories are like viruses
    ● Factories can get too tied
    ● Implicit errors might happen
    ● Factory usage involves a lot of copy/paste with small changes
    ● A poorly designed factory might affect many tests
    ● The tests are created in a way to fit the factory (factory-oriented
    testing)
    ● Developers bump into the same issue again and again
    ● The same hack has to be done several times

    View Slide

  27. @cmaiacd
    Bad factories are like viruses

    View Slide

  28. @cmaiacd
    1. FACTORIES SHOULD REPRESENT THEIR
    MODELS

    View Slide

  29. @cmaiacd
    BAD ❌

    View Slide

  30. @cmaiacd
    GOOD ✅

    View Slide

  31. @cmaiacd
    2. DO NOT RELY ON DEFAULTS FROM
    FACTORIES

    View Slide

  32. @cmaiacd
    ● If a default value is changed, all tests that
    depend on it will break
    ● The setup of a test should contain all the logic
    to ensure it will always pass
    ● Explicit better than implicit

    View Slide

  33. @cmaiacd
    BAD ❌

    View Slide

  34. @cmaiacd
    GOOD ✅

    View Slide

  35. @cmaiacd
    3. FACTORIES SHOULD CONTAIN ONLY THE
    REQUIRED DATA

    View Slide

  36. @cmaiacd
    If the field is nullable (null=True) the
    attribute should be under a trait and not as a
    default value

    View Slide

  37. @cmaiacd
    BAD ❌

    View Slide

  38. @cmaiacd
    GOOD ✅

    View Slide

  39. @cmaiacd
    ● If we want to have an author, we can use
    PollFactory(with_author=True) now
    ● When are we going to remember to test the case
    PollFactory(author=None)?
    ● We should not assume there is an author when
    DB actually allows to not have it.

    View Slide

  40. @cmaiacd
    4. BUILD OVER CREATE

    View Slide

  41. @cmaiacd
    ● MyFactory.build()
    creates a local object (memory)
    ● MyFactory.create()
    creates a local object + stores it in the DB

    View Slide

  42. @cmaiacd
    BAD ❌

    View Slide

  43. @cmaiacd
    GOOD ✅

    View Slide

  44. @cmaiacd
    BUILD STRATEGY
    ======================== 14 passed in 1.76 seconds =========================
    CREATE STRATEGY
    ======================== 14 passed in 3.26 seconds =========================

    View Slide

  45. @cmaiacd
    5.
    IF FK IS IN THE TABLE:
    SUBFACTOR
    IF FK IS IN THE OTHER TABLE:
    RELATEDFACTORY + TRAIT

    View Slide

  46. @cmaiacd
    ● SubFactory: builds/creates the
    SubFactory during the process of
    creation of the main factory
    ● RelatedFactory: builds/creates the
    RelatedFactory after creating the main
    factory

    View Slide

  47. @cmaiacd
    Good ✅

    View Slide

  48. @cmaiacd
    6. USE FIXTURES TO WRAP FACTORIES TO
    AVOID DUPLICATION

    View Slide

  49. @cmaiacd
    BAD ❌

    View Slide

  50. @cmaiacd
    GOOD ✅

    View Slide

  51. @cmaiacd
    7. AVOID SHARING FACTORIES OR
    FIXTURES AMONG DIFFERENT FILES

    View Slide

  52. @cmaiacd
    ● Many tests depending on the same
    factory/fixture
    ● Tends to inflate the factory/fixture
    ● Hard to maintain
    ● Change a factory/fixture => tons of tests
    breaking
    ● Fixture/Factory-oriented testing

    View Slide

  53. @cmaiacd
    Código
    Code

    View Slide

  54. @cmaiacd
    1. Factories should represent their models
    2. Do not rely on defaults from factories
    3. Factories should contain only the required data
    4. Build over create
    5. If FK is in the table: SubFactor
    If FK is in the other table: RelatedFactory + trait
    6. Avoid sharing factories or fixtures among different files
    7. Use fixtures to wrap factories to avoid duplication
    Review

    View Slide

  55. @cmaiacd
    Documentation
    https://factoryboy.readthedocs.io/en/stable/
    Common recipes
    https://factoryboy.readthedocs.io/en/stable/recipes.html
    Code
    https://github.com/FactoryBoy/factory_boy
    Links

    View Slide

  56. @cmaiacd
    THANK YOU!
    @cmaiacd camilamaia
    󰠁
    cmaiacd.com

    View Slide