DjangoCon 2022 | factory_boy: testing like a pro

Video Statistics and Information

Video
Captions Word Cloud
Reddit Comments
Captions
hello everybody I hope you can hear me well uh so let's talk about Factory buy today um first things first uh this is lights deck are already in the speaker rack.com see my CD so if you can see any code or anything you can follow the presentation uh online so um yeah let's go so first of all who am I um as uh as I said already so I'm a back-end developer I work for SoundCloud I'm a Brazilian any Brazilians here wow Jesus Christ I thought we had more right okay sir uh I live in Berlin anyone living in Berlin here thank you so I just relocated to Berlin like uh six months or so so if you want to sheds change an experience like python stuff please uh send a message I'm queer any queer here from Berlin maybe not okay uh I do live with my wife and a dog anyone with a wife and no no okay stop just okay uh so I'm coding since 2010 a long time mostly with python and Ruby um I love to work with communities so conference open stars and stuff I helped to organize a lot of different conference python Brazil I happen on Europe python to 2020 yes and I hope to I also helped to create uh pajamas and help organizing um I like to work with open source as I already said uh one of the main projects that I worked that I work is a scan API that uh this project I created and I helped to maintain basically it's like a framework to create automated documentation for snpis and also integrate to create integration tests so if you are interesting true about this uh this this Library uh we are going to have like a workshop tomorrow uh here in Jungle con so just join me also yeah change the order of the slides but anyways like have more than 1.5 K downloads per month so it's like super nice I'm super proud and it's like really can't feel this number so and more like a lot of stars and okay whatever so anyway this is me hello so let's start with Factory boy what is it I'm super glad that we have already a lot of talks about testing before so I think you are probably already in the vibe of testing and TTD and so yeah but let's talk specifically about Factory boy uh it's a fixture replacement so it's a library and it's basically the idea is to stop using fixtures and starting using factories um with it so it's based on Factory bot that is a gem for Ruby and basically it's like the python version for it it's the factory bot is uh strong fat bots so quite nice company also and the version the first version for a factory boy they were only that it was only for Jungle it was only working for Jungle but now now does it nowadays its framework independent so it works with a lot of different Frameworks and also like workers unit tests by tests and so on um the idea here is that we are talking about specifically in this this talk uh when we are dealing with complex objects so when we have objects models that have a lot of relationships and they are like complex and depending a lot of each other so in this case especially in this case like fixtures can be like a really not that good solution because they are static they are hard instrument and in the other hand like factories they are easy to use they are easy to customize and you can pass only the fields and you can already create your object so just a small example of how we can do this this is like from the factory board documentation basically is like one let's say here that we have an orders object and these others objects is super complex so it depends on address and depends on customer and Depends a lot of other stuff and with Factory boy you can create it only like in instantiating an object uh like a factory a factory for that and without you have to like to create the address create the customer and do all this setup every time for every test that you want so it's like pretty handful um and also one thing that I like from Factory boys that we there is a lot of different tools that comes with it so we can have sequence for example let's say that you have once you create many many users and then but the email field is required for this user so you cannot create all the emails with the same uh with with the same string so let's say that once you create like user one user two user3 dynamically so you can use sequence you can use flaker which is quite quite powerful that is basically to create a random random information so let's say that you want to create an address like a Us address so you can create use Faker for it and it will generate like a random fake a random data for you like create a faker sentence a faker name and then you can like have proper values but also random and many others that I'm just listing here so you can check later but still like you have a lot of different tools for it so my experience in working with Factory boy was like mainly like working three years like in the previous job I was working for working with a really huge monolith were written in Django and that and that we were using Factory boy and basically it was pretty huge because like it was more than 230 models tables uh more than 2200 relevant files and more than 75k relevant line so it was like a monster really and it was like pretty pretty hard to deal with it because uh if you change something it breaks everything so you really need to know where to touch there so a monster and uh and then like starting working with it I I started like figure out some some things that were happening like first thing was that if you design a factory that's not well defined like it's not following some principles it starts affecting many many tests because everything starts depending on it and then you you start having a chain of problems also you might generate implicit errors because if if someone understands a model in a one way and then you create a factor that doesn't match with the model probably the person that will use it it's even if it's you in the future you would assume that it works like the model but if not then probably you're going to create like different errors that you wouldn't expect also uh we're starting like to notice that um a lot of times we were like creating the tests to fit the factory so the factory was like not well designed and then we were trying like to do all the all the the fixes to make the the test Pass based on the in the factory not the way the other way around that usually we would like write a test and just use the factory as a helper so you can use and have other functionalities uh so this is what what I call as Factory oriented tests so they started like doing the testing just to pass like just to match the factory so not not a good approach um also the factors can get too tight so you when you have one Factory and this Factor depends on another in a not really good way then you cannot start changing one because then it affects the other and the other and then you just can really change anything because otherwise you start breaking everything else um and another thing is that when you start like working with a not so good Factory and you see a problem you try to fix it you do a hack because if you change it it will break everything so you do a hack to make it pass but then you're going to work again in another test that use the same Factory and then you have to do the same hack and then in that scenario we were doing the same hack many times really copy paste everywhere and we are just already like copying all the the blocks already because we are super users to copy and paste them same hack over and over again uh so and then I started like you know this is okay we have some patterns here we have we're having we're facing some problems and uh let's let's try to understand what are the root cause and how how we can fix then so uh while we were analyzing this part like I started saying oh maybe we should start taking notes of this and take notes of this and started like really writing some best practices so if we can follow them then in the future um so before I started talking about uh the best practice itself I'm going to introduce the demo app this this app is just like to uh to use as an example uh because of course as I said in the beginning uh this makes sense for complex objects but if I show here a complex app nobody would understand anything because we would take like five minutes only to understand the relationships so I'm going to show like a really simple example just to illustrate the idea of having like complex sublins and factories nice so this is the application basically um a jungle App application uh jungle applications super basic uh this is the post uh page and where we have a list of posts and basically like you can vote on a poll so let's say that we want to vote if we prefer like Coke or Pepsi whatever so if we vote here then we go to the to this page to vote and then we can click on vote and if we click on vote we see the results and that's it basically and just taking a look in the in the the first screen uh there are some some details here that we we should notice the first one is this label that is new that basically says that every time that there are a poll is was created like in this last 24 hours then we have this label and another thing is that if the post premium then it has like a star it just should differentiate it also Apple can have or not an altar so for example in this first shoe we have an outer um but in the last two we don't and also we can have poles in two different languages one uh is English or Portuguese and if it's uh English we are going to use the proposition for the author as by but if it's uh Portuguese we are going to use pork so basically this is the logic of the of the application this is all the logic that we have uh talking about the relationships between them we have Paul that basically have the published date um and if it's premium or not um related with the question that has the question itself so it's text and also we have the language that is a chart field saying if it's English or Portuguese and the question can have known or many choices so a choice have a text saying like what's the option for the person to vote and also the number of votes or the total votes cool uh here is the model so this is the pro model as I said already in the beginning uh in the last slide we have the attributes so basically question it's 101 publish date author and premium and also we have it under methods here then the restring that basically is responsible to do all this logic about showing the text of the question uh of the post so gets the information on that question and puts star no star and the outer or not out also we have a method here for the poll that is uh for was published basically to handle the logic of the new label and uh we have questions with all the attributes and also some auxiliary methods just saying if it's in English it's in Portuguese and also to get it string for the choices it's the simplest one that basically the the attributes and the under string which you get the the value okay so let's practice let's go the first one is factors should represent their models actually this is the most important one if a lot of times if you follow this one the others will will also work so basically the idea is that the factory should represent exactly what you have in the database so if you are you if you have a relationship in a database you have you should have in the in the in the factory as well if the value can be new in the database so the factory also so you have to map this the same way so this way you can avoid impressed errors so um and then you in the future and also your your co-workers will know how this Factory works because they already know how the model works so they wouldn't need to guess how the factors works so one example of how we shouldn't do this the first one is uh so we have the pull Factory here and the question Factory so we are saying here that in the questions Factory we are pointing to the poll so but if you see here in the model we have the question but there is no motion to pull at all here because the the relationship is in the other way so this is this is not good because in the model we are we don't have the relationship but in the factory we have so the good way of doing this would be put in the the relationship in the proper place that is imposed so if you go back here and you see that Paul does have the question uh in the relationship so here we met the same relationship second one is do not rely on the phones for factories basically uh this one means that if you have a value in the factory and that you create by default and then you start using and other tests relying that thinking that this value will be always the same then this might generate some problems so for example if someone goes and change the value in the factory it will break your test that it shouldn't also um we should like create a test having the most out setup already there so if anyone changed anything it doesn't matter because on your test you are setting everything that you want so you are being explicit and you are being explicit what you want saying exactly what the value that you want so let's see some example uh we have pull crash a pull Factory and question Factory again and then we have a test the test is just to check if the text of the poll is is valid is right so here a bad example would be to have a default value in the question Factory and saying it explicitly as setting it explicitly as WhatsApp and then in the test in the test you are asserting it directly so you're getting this hard code value and checking if this is like a valid or not so the idea here would be instead of first putting the value as hard coded we could use Faker so it would be always a new different value there and also we should properly say explicitly what we want when creating a factory so here when we are creating a factor we are saying that we want that premium is false we want without alter and we want with this text so we are like this is what I was trying to talk uh talk about saying that we should be expliciting saying everything that you want inside the test so we should do all the setup inside the test uh the third one is factories should contain only the required data this is a uh this is also um related to um representing their models so basically the rule is if if the value in the database uh in the in the in the model says that could be no so no because true then the attribute should be um if you are going to explicitly say that you want this attribute you should put it under a trade so then the user can have an option to use it or not but by default it will be no it exactly the same way as an Aries in the database so let's see an example of how not to do it so we have here question and then we have author so if you go back here and we see question model then there is um there there is the outer what is that question oh it's Paul that's why okay po we have outer but then uh it's no equals true so it means that in the database we can have a poll without an auto and then here we are saying explicitly that every time that you create a factory it will come already with an author even though you didn't explicit say that so the idea would be to put it under a trade so every time that you want an alter then you have to explicitly say that so basically if you want an auto you you would use the factory and this way pull Factory with auto equals true so you're saying that you want an outer otherwise I think it's pretty hard to remember that we should also test the case where the outer is known because this is like we we wouldn't probably remember about passing known as outer so in this way you always remember to test all the cases and and basically because we should not assume that we have an author in the in the factory since in the database we have the possibility of not having an outward so we are like missing one case here uh the fourth one is built over create this is super related with performance uh basically let's see the difference between them when you do like myfactory.build it creates an object in memory but then we do my factory.create it creates a memory but also it stores in the database so basically the idea here is not saying that you should never use create it's just to keep in mind that first if you're using Create you're not doing unit tests anymore you are hitting the database so you're really testing more than just your unit and uh the second one it will take more so if you are okay with this then then so good but I would say that especially for like huge uh test Suites if you use more build probably it will be way faster so if you're using like in the bad way here like bad way uh let's say that if you use a create then you have to pass the notation okay so you should not use grid so how would we do this uh so basically we would use build instead and then how the magical would be done good so just an example of how this can impact your performance we we have a file with 14 tests so really small file 14 tests and using only create it was passing in 3.26 seconds when we change everything to start using build it was less than two seconds so imagine this for like more than 10 000 tests this can really impact so the fifth one this this one took me a while to understand but once I understood the relationship between this helped a lot to make the factories uh not so tight so this happened a lot basically the rule is if there is a firing key in the table then you represent this relationship with a sub Factory if the furniture is in the other table then you use a related Factor under a trade so let's see first the difference between superfactory and related Factory super Factory when you are creating or building a sub Factory it creates at the same time of the main Factory so it occurs in the same time so if they are dependent they will uh they will be done at the same time but in the related Factor it creates first the main factor and then the related Factory so maybe these are the difference so seeing an example here of how we should do this so we have the choices and uh the question Factory so the first one if you see here choice um your choice we can see that we do have the foreign key so if we do have different Keys see this means that the we really depend it's a dependence so we should use a super factor in this so we use a super Factory directly if uh in the case of a question if you go here we see that we don't have the the relationship here uh to the choice so there's no mention of the choice so the foreign key is in the other table in this case so what means is that we can have for this model we can have a question without a choice so for that we would create then a related Factor because the factor will be created afterwards and under the trade so you can also create a factor with choice and without choice because in the database you can create without choice so we should simulate the same for the factory so basically this would be the way that we will create new using their relationships the sixth best practice is we can use fixtures because I was saying in the first and the first slides that we it should like factories being used instead of pictures but we can keep using fixtures like for simple objects for example like things that are not complex but also to avoid duplication so this this best practice is a way of how to use fiction in a pretty good way so basically let's say that we have this example here we have two tests and if you see we are creating this tube test uh two factories two objects from factories but they are passing exactly the same attributes so we are repeating ourselves a lot and imagine if you have a lot of tests this would be a lot of repetition so one good way to do this is like encapsulate this uh using a fixture and then reuse this fixture in the test so you have a pretty clear fixture that is in this case just like I want a poll that is a English and it's no premium and there is an author and then you can reuse it so this is a good way of using the fixture but it's uh this leads us to our last best factor is that we should avoid sharing factors or our fixtures independently among different files why so basically if we start me sharing like having common fixtures common factors nafaya and have a lot of them we're starting creating dependencies a lot so we if we try to change improve or if we try to do anything with this with this these factors or fixtures it will touch in a lot of different place so also it tends to inflate because we have different scenarios where you're using the same fixture or the same Factory and then we are trying to accommodate so we start putting things together things in the same fixture and then it's getting getting bigger and bigger and bigger because you are trying to accommodate all the different scenarios where you shouldn't so also it's hard to maintain especially because if you change a factory fixture you have tons of testing breaking at the same time so you cannot incorporate everything um and also one more time that if you start doing this we will probably will be in a scenario where you are trying to make your test pass only to fit the fixture to match the fixture and not like really thinking about what your test should be doing okay and then we like I started notice the patterns I I saw all the best practices I noticed I took note of everything nice so let's go and let's try to fix the first factory right so I got one of the main factories there and then I saw like yeah why not I will change it I will do like user related Factor when it shoots super Factory nice cool and then I broke more than 1500 plus really it was painful so what I say is first of all babe steps so if it's already too too tight if it's already in a really bad situation probably we are going to have a lot of hard work but let's let's try it with the first thing so the new ones the new factors try to use the best practice because this probably will help and then trying to go Factory by Factory changing step by step because of course this could like be pretty hard but I'm 100 sure that this can help a lot once you have the models and the factories matching and then everything will happen as you would expect um all these examples and the code of this app is in the GitHub repository camera is like Factory Boys best practice uh the official dots of factory boy is here also the common recipes they have a page where they they give some tips like this so you can merge like some of these ones and some of the factory Boy official ones and also the code of the the library itself is here I would like to thank the whole organization because I know how hard it is to organize like a super huge event like this and it's been awesome and then I want to thank you everyone and if you want to talk with me these are my uh social and please let's keep in touch if you have any doubts or any questions or any suggestions about Factory boy just talk with me thank you very much
Info
Channel: DjangoCon Europe
Views: 3,166
Rating: undefined out of 5
Keywords:
Id: -C-XNHAJF-c
Channel Id: undefined
Length: 27min 8sec (1628 seconds)
Published: Sat Oct 15 2022
Related Videos
Note
Please note that this website is currently a work in progress! Lots of interesting data and statistics to come.