Slide 1

Slide 1 text

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

Slide 2

Slide 2 text

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

Slide 3

Slide 3 text

@cmaiacd Who am I?

Slide 4

Slide 4 text

@cmaiacd Brazilian living in Berlin Bachelor of Computer Information System Coding since 2010 πŸ‘΅ Python 🐍 and Ruby πŸ’Ž Open Source and Community ❀ Conferences Backend Developer @ SoundCloud

Slide 5

Slide 5 text

@cmaiacd Creator of ScanAPI

Slide 6

Slide 6 text

@cmaiacd First GitHub profile to be accepted for the GitHub Sponsors program in Brazil σ°Ž™ Quem sou eu?

Slide 7

Slide 7 text

@cmaiacd factory_boy: what is it?

Slide 8

Slide 8 text

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

Slide 9

Slide 9 text

@cmaiacd For complex objects: ❌ Fixtures: static, hard to maintain βœ… Factories: easy-to-use

Slide 10

Slide 10 text

@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

Slide 11

Slide 11 text

@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

Slide 12

Slide 12 text

@cmaiacd Demo App

Slide 13

Slide 13 text

@cmaiacd Polls

Slide 14

Slide 14 text

@cmaiacd Poll

Slide 15

Slide 15 text

@cmaiacd Results

Slide 16

Slide 16 text

@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

Slide 17

Slide 17 text

@cmaiacd Create Question - Admin

Slide 18

Slide 18 text

@cmaiacd Create Question - Admin

Slide 19

Slide 19 text

@cmaiacd Questions - Admin

Slide 20

Slide 20 text

@cmaiacd Model - Poll

Slide 21

Slide 21 text

@cmaiacd Model - Poll

Slide 22

Slide 22 text

@cmaiacd Model - Question

Slide 23

Slide 23 text

@cmaiacd Model - Choice

Slide 24

Slide 24 text

@cmaiacd Best Practices

Slide 25

Slide 25 text

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

Slide 26

Slide 26 text

@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

Slide 27

Slide 27 text

@cmaiacd Bad factories are like viruses

Slide 28

Slide 28 text

@cmaiacd 1. FACTORIES SHOULD REPRESENT THEIR MODELS

Slide 29

Slide 29 text

@cmaiacd BAD ❌

Slide 30

Slide 30 text

@cmaiacd GOOD βœ…

Slide 31

Slide 31 text

@cmaiacd 2. DO NOT RELY ON DEFAULTS FROM FACTORIES

Slide 32

Slide 32 text

@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

Slide 33

Slide 33 text

@cmaiacd BAD ❌

Slide 34

Slide 34 text

@cmaiacd GOOD βœ…

Slide 35

Slide 35 text

@cmaiacd 3. FACTORIES SHOULD CONTAIN ONLY THE REQUIRED DATA

Slide 36

Slide 36 text

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

Slide 37

Slide 37 text

@cmaiacd BAD ❌

Slide 38

Slide 38 text

@cmaiacd GOOD βœ…

Slide 39

Slide 39 text

@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.

Slide 40

Slide 40 text

@cmaiacd 4. BUILD OVER CREATE

Slide 41

Slide 41 text

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

Slide 42

Slide 42 text

@cmaiacd BAD ❌

Slide 43

Slide 43 text

@cmaiacd GOOD βœ…

Slide 44

Slide 44 text

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

Slide 45

Slide 45 text

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

Slide 46

Slide 46 text

@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

Slide 47

Slide 47 text

@cmaiacd Good βœ…

Slide 48

Slide 48 text

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

Slide 49

Slide 49 text

@cmaiacd BAD ❌

Slide 50

Slide 50 text

@cmaiacd GOOD βœ…

Slide 51

Slide 51 text

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

Slide 52

Slide 52 text

@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

Slide 53

Slide 53 text

@cmaiacd CΓ³digo Code

Slide 54

Slide 54 text

@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

Slide 55

Slide 55 text

@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

Slide 56

Slide 56 text

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