Why you need a separate test database
53sClear, practical tip for developers on avoiding test data pollution.
▶ Play ClipThis tutorial demonstrates a complete test setup for a Symfony API Platform REST API using PHPUnit. The creator walks through creating a dedicated test database, loading fake fixtures with Alice, and writing automated tests to verify CRUD endpoints, pagination, JSON schema, and validation rules—all without leaving the code editor.
The video focuses on setting up API testing with a separate test database, using packages for request simulation and JSON schema assertions.
A separate test database prevents polluting the dev DB and ensures every test starts from the same clean state, avoiding failures caused by other developers' data.
Command: `symfony console --env=test doctrine:database:create`. This appends '_test' to the database name (e.g., `products_api_test`).
Command: `symfony console --env=test doctrine:migrations:migrate` creates the tables (manufacturer, product) in the test DB.
Installed via Composer: `alice` (fixture generation), `symfony/test-pack` (PHPUnit + bridge), `symfony/http-client` (request simulation), `json-schema` (JSON schema assertions).
YAML fixture files for Manufacturer and Product define entity classes, field values (e.g., company name, description, country code, date). Products reference Manufacturers using notation like `manufacturer: '@manufacturer_*'`.
Command: `symfony console --env=test doctrine:fixtures:load`. Must run in `test` environment to avoid populating the dev database.
Create `products_test.php` in `/tests/`. Extend `ApiTestCase` (from API Platform) and use `RefreshDatabaseTrait` to purge/fixture-load before the first test and wrap all tests in a rollback transaction.
Test `test_get_collection`: create client, send GET to `/api/products`, assert 200 response, check `Content-Type` header (`application/ld+json; charset=utf-8`), and validate JSON subset (context, ID, hydra:view).
Using `assertJsonContains()` with an array that includes `@context`, `@id`, and pagination keys (`hydra:view` → `@id`, `type`, `hydra:first`, `hydra:last`, etc.).
Default pagination differs from expected; fixed by adding `pagination_items_per_page=5` attribute on the Product API resource.
Add `<server name='SYMFONY_DEPRECATIONS_HELPER' value='disabled'/>` to `phpunit.xml.dist` under `<php>` to remove deprecation output.
Use `assertCount(5, $response->toArray()['hydra:member'])` to verify the page returns exactly 5 products.
Test `test_pagination`: request `/api/products?page=2`, assert that `hydra:view` contains `@id` with page=2, `hydra:first`, `hydra:last`, `hydra:next` (page 3), and `hydra:previous` (page 1).
Test `test_create_product`: POST to `/api/products` with JSON body (mpn, name, description, issueDate, manufacturer: '/api/manufacturers/1'). Assert 201 status and check response body contains the same fields.
Noticed issueDate was not writable in the entity → added `@ApiProperty(writable=true)` or `product:write` group to allow POSTing it.
Test `test_update_product`: PUT to `/api/products/1` with updated description, assert 200 and that the returned JSON reflects the change.
Test `test_create_invalid_product`: POST with `manufacturer: null`. Initially got 201 (created), revealing missing `NotNull` constraint. Adding `@Assert otNull` on manufacturer fixed it, making the test expect 422.
The test revealed that manufacturer writable group was missing. Adding `manufacturer` to the write group or using `@ApiProperty(writable=true)` allowed the POST with a manufacturer IRI to work.
Tests can drive development: stay in code editor, write tests, fix code based on failures, and avoid constantly switching to Postman or UI.
The video demonstrates a complete testing workflow for a Symfony API Platform app using PHPUnit, including database isolation, fixture loading, and endpoint validation. End-to-end tests catch bugs early and allow developers to build and refine APIs without leaving the IDE.
"The title accurately describes the content: it is Part 13 of a crash course and fully delivers a step-by-step guide to testing an API with PHPUnit."
Why is a separate test database recommended?
It prevents polluting the development database with test data and ensures each test starts from the same clean state.
0:22
What command creates the test database in Symfony?
`symfony console --env=test doctrine:database:create`
1:46
Which package generates fake fixture data in Symfony tests?
Alice (DoctrineFixturesBundle's Alice).
3:01
What is the purpose of the `RefreshDatabaseTrait`?
It purges and reloads fixtures before the first test and wraps each test in a transaction that is rolled back, so every test starts with the same fixture data.
7:56
How do you assert that a response contains a subset of JSON in API Platform tests?
Using `$client->assertJsonContains([...])` with an array of expected keys/values.
9:43
What command migrates the schema to the test database?
`symfony console --env=test doctrine:migrations:migrate`
2:30
How can you silence deprecation notices in PHPUnit output?
Add `<server name='SYMFONY_DEPRECATIONS_HELPER' value='disabled'/>` to `phpunit.xml.dist` under the `<php>` section.
11:22
How do you count the number of items on a page in a test?
Use `assertCount(5, $response->toArray()['hydra:member'])`.
12:09
What status code should a successful POST to create a resource return?
201 (Created).
14:40
How do you pass the manufacturer relation when creating a product in a test?
Include `manufacturer: '/api/manufacturers/1'` in the JSON body, and ensure the manufacturer property is writable (e.g., with `@ApiProperty(writable=true)` or a write group).
15:22
Test database isolation
Explains a best practice for reliable API testing: a separate test database that starts in the same clean state for every test.
0:22RefreshDatabaseTrait
Introduces a powerful trait that fully automates fixture reloading and transaction rollback, dramatically simplifying test setup.
7:56JSON subset assertion
Demonstrates a flexible way to verify API responses without requiring an exact match, focusing only on the relevant parts.
9:56Test catches missing validation
Shows how a failing test revealed that the `NotNull` constraint and writable group were missing for the manufacturer field, preventing a validation error from being thrown.
18:45TDD-like workflow with tests
Emphasises the benefit of letting tests guide code changes, reducing the need to switch between the IDE and external API clients like Postman.
21:36[00:00] in this one we're going to have a look
[00:01] at testing our api so we'll get a nice
[00:03] test setup created we'll have a test
[00:06] database we'll pull in some packages
[00:07] which are going to help us
[00:09] make those requests or simulate requests
[00:11] to our api and also
[00:13] make assertions against the schema or
[00:15] the json which we get back so the first
[00:19] thing we're going to do is actually set
[00:20] up our test database because i think
[00:22] it's important to have a separate test
[00:24] database not essential but it means that
[00:27] you're not polluting your development
[00:29] database with test
[00:31] data and also it means we can have a
[00:33] setup which starts in the exact same
[00:36] state for every test so that you don't
[00:38] have other developers are like adding
[00:40] new records in there which make your
[00:42] test fail things like that choose high
[00:44] definition for the best viewing
[00:46] experience and if you'd like to join a
[00:48] growing group of software developers and
[00:49] take your skills to new level all you
[00:51] need to do is subscribe click the little
[00:53] notification icon and welcome now you
[00:56] may or may not be familiar with symphony
[00:58] already but i'll show you how the test
[01:00] database
[01:02] setup works in there so if we go back
[01:03] and have a look at our emv file where we
[01:07] determined our database url here and we
[01:10] said that our database name will be
[01:12] products api if we go over to the config
[01:15] folder here
[01:17] and in packages
[01:19] test
[01:20] doctrine dot yaml you'll see that we
[01:23] have db name suffix so ignore this part
[01:26] on the end here this environment
[01:28] variable thing but what we're looking at
[01:30] is this so what that means it will
[01:32] append
[01:33] the word underscore test onto the end of
[01:37] your database and so we're gonna just
[01:39] run a couple of commands and that will
[01:41] create us a test database with that name
[01:44] so back to our notes the command that we
[01:46] need in order to create our test
[01:48] database is this one so i'll paste it in
[01:50] my terminal and i'll explain this to you
[01:53] so symfony console is all the same as
[01:55] when we created our development database
[01:57] except here after symphony console we're
[02:00] saying
[02:01] emv equals test and then by doing that
[02:05] it will then create us a test
[02:07] environment database let's hit go
[02:12] okay and so he's saying he's created
[02:13] products api test database i'm going to
[02:16] go over to table plus and just make sure
[02:18] that i have that there
[02:21] okay and so here's my products api test
[02:24] database obviously there's no tables in
[02:26] there yet because we need to go and
[02:28] migrate our schema let's go and do that
[02:30] next so the next command is this one
[02:33] symphony console and again we're passing
[02:36] m test and it's just a doctrine
[02:38] migrations migrate i'll copy them copy
[02:41] that paste that in there
[02:43] run that
[02:44] and it asks me if i'm sure i'll just say
[02:46] yes
[02:49] okay and so it's saying that it's
[02:51] migrating my database let's go back to
[02:53] table plus refresh
[02:55] great stuff so now we have a
[02:56] manufacturer table and a product table
[03:00] the next thing i'm going to do is i'm
[03:01] going to composer require some packages
[03:04] and they are alice
[03:06] uh because we're using simplyflex we can
[03:08] just use a short name for these so alice
[03:11] symphony test pack symphony http client
[03:15] and something called json schema so what
[03:17] are these alice is used to generate fake
[03:20] fixture data
[03:22] symphony test pack includes php unit and
[03:24] php unit bridge
[03:26] http client is what the api platform
[03:30] test client is built on so http client
[03:33] is a symphony component for making
[03:36] requests and json schema provides json
[03:39] schema test assertions okay so let's go
[03:43] and pull that in
[03:46] [Music]
[03:56] the next thing i'm going to do is set up
[03:57] some test fixtures so inside of a
[04:01] fixtures folder which you see here just
[04:03] gonna add a yaml file for the
[04:05] manufacturer and one for the product
[04:22] and so i'll just paste in something
[04:23] which i've previously created should be
[04:25] self-explanatory this is saying that
[04:27] this is the entity or the model that
[04:29] this is based on this is what can be
[04:31] used uh to reference um each particular
[04:35] record so we'll be able to reference
[04:37] manufacturer from our product fixtures
[04:39] and then here is how we create each of
[04:43] the fields so this is just going to give
[04:44] it a company name
[04:46] this will just provide some text for the
[04:48] description uh it will generate a
[04:50] country code for the country code and a
[04:53] date time for the listed date so now
[04:55] let's go over to our product fixture or
[04:58] product yaml file and we'll do the same
[05:00] here
[05:01] okay so let me just talk you through
[05:03] this for it's the same as what we did
[05:05] for the manufacturer so again our entity
[05:08] is the product and then we're going to
[05:10] create a hundred this time so what this
[05:11] is is uh we're creating products from
[05:14] number one to 100 mpn i've just used
[05:18] isbn because that's probably the closest
[05:20] thing i can think of that there's no
[05:22] no special
[05:24] item in faker in order to generate
[05:27] mpn so i'm just using that uh name i've
[05:30] just gone with catchphrase these things
[05:32] aren't really that important description
[05:34] just creating a sentence made up of six
[05:37] words uh issue date again using the date
[05:40] time manufacturer because if you think
[05:42] about our products we can't create
[05:44] products without manufacturer so what
[05:46] this will do is it will just reference
[05:49] manufacturers from our manufacturer yaml
[05:52] file here so where we're saying
[05:54] manufacturer underscore 1 to 10 what
[05:57] this will do is it will reference
[06:00] one of those for each of the products
[06:02] i'll go back to my notes file and so we
[06:05] have a command here which will load our
[06:08] fixtures that we just created so grab
[06:10] this
[06:11] and then i'll go and paste this in here
[06:16] and again make sure that you are in test
[06:19] environment when you run this otherwise
[06:21] you'll end up populating your
[06:22] development database okay let's hit go
[06:28] and i'll ask you if you want to continue
[06:31] okay so these notices here there's just
[06:33] a deprecation notice i'll show you how
[06:36] we can get rid of these for our tests
[06:38] but it's not come back with any errors
[06:40] so that's telling me that this has
[06:42] actually worked first time which is a
[06:44] bit of a miracle because
[06:46] that has rarely happened before refresh
[06:48] okay great stuff so it looks like we
[06:51] have 100 products perfect and we also
[06:54] have 10 manufacturers we'll just check
[06:56] the manufacturer ids on our products yep
[06:59] they run one to ten okay so that's
[07:02] worked uh perfectly first time great
[07:04] stuff we're now ready to actually go and
[07:06] start writing our tests i think
[07:08] so the folder is tests and in here we'll
[07:11] just create one test so i would normally
[07:13] split things down into like product uh
[07:15] sorry unit test and feature test and
[07:17] things like that but i'm only going to
[07:18] create one test here because i'm just
[07:20] showing you how you can do this uh if
[07:23] you're building your own api then
[07:25] obviously you'll go and
[07:26] put a bit more effort into your folder
[07:28] structures and things like that so we'll
[07:30] call this products test
[07:32] [Music]
[07:36] and this will extend a test case
[07:38] called api test case
[07:42] and that will give us uh some of the
[07:44] tools we need so things like being able
[07:47] to simulate the http request we'll have
[07:49] a client and also some uh api specific
[07:53] assertions will be available to us in
[07:56] order for all tests to start the same
[07:57] state we're going to pull in a little
[07:59] trait here called refresh database trait
[08:02] and we're just going to have a little
[08:04] look in the comments and see what it
[08:05] says about this basically saying that it
[08:07] purges and loads the fixtures uh before
[08:09] the first test and wraps all the tests
[08:12] in the transaction that we roll back
[08:14] when it is finished so that means that
[08:16] each test in our
[08:18] products test will start in exactly the
[08:20] same state with the same
[08:21] fixtures loaded
[08:24] okay so i'm going to add a test for
[08:25] getting a collection so test
[08:28] get
[08:30] collection so here we're gonna get a
[08:32] collection of products
[08:35] and the way i can do that is like this
[08:37] so static
[08:39] and then
[08:41] create client so that will give us our
[08:43] http client and then we're going to send
[08:46] a request which will be
[08:49] a get request so the method is the first
[08:52] argument the second argument is the url
[08:56] so that will be for us api
[09:00] products i can check for a successful
[09:03] response like this
[09:06] assert response is successful and that's
[09:08] all i need to do there i can check
[09:11] headers
[09:12] [Music]
[09:16] so assert response header same
[09:20] and so we shall say content
[09:23] type
[09:24] and i expect it to have this value here
[09:27] application for slash ld plus json
[09:31] semicolon
[09:32] character set is utf-8 utf-8
[09:36] and then i can actually make assertions
[09:38] about the body so
[09:40] this
[09:41] assert
[09:43] jason i'm looking for adjacent contain
[09:46] so i'm not looking for an exact match
[09:48] i'm just making sure that the json which
[09:50] comes back does contain a subset which i
[09:53] specify
[09:54] and so here
[09:56] you can pass it in array format and i'm
[09:58] just going to paste in
[10:00] some work which i've previously done
[10:02] because you don't want to see me type
[10:03] all this out and so we're asserting that
[10:06] our json should contain this subset here
[10:09] so it's all the stuff that you've seen
[10:11] using postman using the user interface
[10:14] thing we're looking at our context our
[10:16] id and then we've also got stuff
[10:19] regarding our pagination here under the
[10:22] hydra view
[10:23] and so i'm going to run this test
[10:25] initially but i'm expecting this to fail
[10:27] because i've not actually set up
[10:29] pagination on my product yet so let's go
[10:32] and run this
[10:33] [Music]
[10:38] okay and so look for our failure and
[10:41] here we're getting uh incorrect
[10:43] pagination because it's just my product
[10:46] is currently using in default pagination
[10:48] so in order to be able to test that and
[10:50] to demonstrate it i really want to
[10:52] set up my own pagination so we'll go
[10:54] over to product
[10:56] and here under our api resource i'm just
[10:59] going to add a new one and i'm just
[11:00] going to borrow the one from
[11:02] manufacturer so attributes pagination
[11:04] items per page is 5 which should
[11:08] make my test pass so we should now get
[11:12] 20 pages in total the last page should
[11:14] be 20 because 500 sorry 100 divided by 5
[11:18] should give us 20. let's go and run this
[11:22] okay and this time we are green so
[11:24] you'll see that we're getting these
[11:26] deprecation notices here which i
[11:28] mentioned earlier if we go to our notes
[11:31] i've actually got a piece or a line
[11:34] which we can add to our php unit file so
[11:37] go over to phpunit xml dist which you'll
[11:41] find in your project root
[11:44] and just in here see where you see have
[11:46] the php tags and you have these server
[11:50] variables just drop that underneath
[11:53] there
[11:54] and all saying is just disable our
[11:56] symphony deprecations helper let's go
[11:59] and run this again
[12:01] okay so this time we get our one test
[12:04] three sessions but we don't have those
[12:06] uh annoying deprecation notices in the
[12:08] way
[12:09] let's go and make an assertion about the
[12:11] number of items which are returned so in
[12:13] order to do this i'm just going to grab
[12:15] a response here
[12:20] and what i'll do because we're filling
[12:22] up our page a bit is i'll make my font a
[12:24] little bit smaller so we'll go with
[12:27] 22
[12:30] okay and then just down here
[12:33] i can say this
[12:36] assert
[12:37] count
[12:38] because we're counting the items in an
[12:40] array
[12:41] we should get five items and if i say
[12:44] response
[12:45] to array it will take our response and
[12:47] convert it to an array and then we can
[12:49] count certain items and we're going to
[12:52] count hydra members
[12:56] okay one test for assertions this time
[12:59] so i'm happy with that test let's now go
[13:01] and test pagination so we'll hit another
[13:04] endpoint except this time we'll head for
[13:06] uh page two will append page two or page
[13:08] three or something on the end of that so
[13:13] [Music]
[13:15] test
[13:16] pagination
[13:17] [Music]
[13:21] okay i'm gonna go and borrow some of
[13:22] this stuff here
[13:24] so
[13:25] uh
[13:26] i'll go and grab it all but we'll just
[13:28] edit out the stuff that we don't really
[13:30] need all i want to look at here really
[13:32] is the keys that we get here for our
[13:34] pagination so we're going to make the um
[13:38] request we'll get a response i'll not
[13:40] bother checking headers we know that all
[13:42] that stuff works what we're going to do
[13:44] here though is say
[13:46] page equals two
[13:49] and so that means that some of these
[13:50] things will change we're getting back
[13:52] page two
[13:53] first will remain the same last will
[13:55] remain the same next will be three but
[13:58] we also want a previous so
[14:01] i'll just drop that down there i'll say
[14:04] hydra
[14:06] previous
[14:08] and that will be page
[14:11] one
[14:12] and i'll not bother doing a count
[14:14] so yeah like i say basically i'm just
[14:17] looking to make sure that we get the
[14:19] correct pagination details back let's go
[14:22] and run this
[14:26] okay to test five assertions let's just
[14:28] change some of these values change this
[14:30] to 18 for example just to make sure
[14:34] okay and it failed so that's good
[14:36] change that back and we'll test
[14:38] something else let's create a product
[14:43] test create product
[14:50] okay so similar to making a get request
[14:53] all the uh
[14:54] we require the http client we make the
[14:57] request that's up this time we're going
[14:59] to make a post request so request and
[15:02] the method will be post and so we're
[15:04] going to need some more information this
[15:06] time the url
[15:08] will be
[15:10] the same so posting to api
[15:12] [Music]
[15:15] products
[15:16] but now we're going to need an array and
[15:18] we're going to say json
[15:20] and then we're going to pass an array
[15:23] of all of the properties all the fields
[15:25] which we will which we wish to fill on
[15:28] our newly created product
[15:30] so i've just come and pasted some stuff
[15:32] in there behind the scenes
[15:34] all the usual stuff mpn name description
[15:37] issue date the only risky
[15:40] strategy i'm taking here is i'm making
[15:42] the assumption that we have a
[15:45] manufacturer with an id of one in our
[15:47] test fixtures which we created so i do
[15:50] know that i have that however if we were
[15:52] to refresh this or run this again then
[15:56] because it's a auto increment in id
[15:58] would actually start from 11 months so
[16:00] it means that i wouldn't have a
[16:02] manufacturer id of one so i'm not going
[16:04] to change it i'm going to leave it the
[16:06] way it is but it's just to let you know
[16:08] that this is probably
[16:10] could be done better the way you could
[16:13] do it better will be to actually make a
[16:15] request actually send a request off to
[16:18] retrieve a manufacturer and just use the
[16:20] um id for the first manufacturer that
[16:23] you get back but that's just a little
[16:25] hint or a little tip there that you
[16:26] could use
[16:28] this time our response code should be a
[16:30] 201 so this
[16:33] assert
[16:38] set response status code at the same two
[16:41] zero one
[16:43] headers should be the same as the last
[16:45] test so or the first test so we'll just
[16:48] go and grab that
[16:54] okay so while i was recording this i
[16:56] noticed an issue and that was that the
[16:59] issue date wasn't writable which meant
[17:01] that we weren't going to
[17:02] be able to write that to the database
[17:04] when we did this so go over to your
[17:06] product and make the issue date also
[17:09] writeable by saying product write we'll
[17:12] make some assertions about the response
[17:14] body so again a cert
[17:16] json contains
[17:24] and so we're just looking to make sure
[17:26] that all these things are correct the
[17:27] only thing i've made a bit different
[17:29] here is that this is a format that the
[17:31] issue date is going to come back in even
[17:33] though we sent it off in this format so
[17:36] um just something to be aware of there
[17:38] let's actually go and run this and see
[17:40] how we get on
[17:43] okay so we get three tests eight
[17:44] assertions so you should be getting the
[17:46] gist of this now rather than see me type
[17:48] out these tests in full what i'll do is
[17:50] i'll just paste them in and explain my
[17:52] way through them as we go
[17:55] okay this time we're testing that we can
[17:57] update a product so test update product
[18:00] setup is the same
[18:01] client create client we're making a put
[18:04] request but this time notice we've
[18:06] appended on
[18:08] a
[18:09] id for the product which we want to
[18:11] update whereas when we created a product
[18:13] and we just needed to hit the endpoint
[18:16] api products this time we need to
[18:18] specify which product is going to be so
[18:20] i've gone with api products number one
[18:23] and then
[18:25] we're just gonna update the description
[18:27] so here we're saying an update is
[18:29] description
[18:30] and then check that we get a successful
[18:33] response and then we're just checking
[18:35] the json which comes back let's go and
[18:38] run this
[18:41] okay so that's good then we'll do one
[18:44] final test to we'll try and actually uh
[18:47] trigger some validation errors by
[18:50] sending incorrectly formatted uh body
[18:53] content or something like that and so
[18:55] this is the test that i've created for
[18:56] this test create invalid product and
[18:59] i've picked this uh case specifically
[19:02] because i noted i noticed a mistake in
[19:04] my code and so what i'm going to do is
[19:06] i'm going to go and fix that but i'm
[19:07] going to try without using a test so
[19:10] here i'm saying static create client
[19:13] we're making a post request to products
[19:16] and then we're going to create
[19:18] a product and this time i'm passing
[19:21] manufacturer null which really we should
[19:24] have to pass a manufacturer in order to
[19:27] create a product record because a
[19:28] product must have a manufacturer but
[19:30] let's just go and see what happens when
[19:32] i run this
[19:36] okay so i'm expecting a validation error
[19:39] so here this search response status code
[19:42] same four two two however that's not
[19:45] what i'm getting back it's saying failed
[19:47] asserting that
[19:49] the response status code is 422 if you
[19:52] notice here the response status code is
[19:55] 201 created which means it's been able
[19:58] to go ahead and actually create that
[20:00] record which tells me that there's a
[20:02] problem with my code so the first thing
[20:04] i'm going to do is i'm going to go over
[20:06] to product and just have a look at this
[20:09] and i'm going to put an not null
[20:11] assertion in here so assert not null
[20:15] we'll drop that in here
[20:20] okay and then we'll go and run the tests
[20:22] again and see what it tells us
[20:26] okay and this time we have another
[20:28] failure
[20:31] failed asserting that response status
[20:33] code is 201
[20:35] on line 68 of products test so what's
[20:38] going on here let's go over to products
[20:40] test and we're looking at line 68
[20:45] so here
[20:46] where we're saying assert response
[20:48] status code same two or one that's not
[20:51] what we're actually getting we're not
[20:52] actually creating uh that record
[20:55] and the reason is even though we're
[20:57] passing a
[20:59] manufacturer's string here we haven't
[21:01] actually enabled right
[21:03] for manufacturer on our product so what
[21:06] i'm going to do is we're just going to
[21:07] go and
[21:11] add that now
[21:13] and we'll tidy this up a bit because
[21:15] it's getting a little bit messy we'll
[21:16] drop this onto its own line
[21:19] okay back to our test let's run it and
[21:21] see where we get this time
[21:25] and so that tells us that we are getting
[21:27] a two or one saying the product has been
[21:28] correctly created and it's also being
[21:31] correctly created with that manufacturer
[21:33] id as well
[21:34] and so we'll leave it there hopefully
[21:36] that's been helpful you've probably been
[21:38] able to see that you could actually
[21:40] build your entire application just by
[21:42] using tests it means we don't actually
[21:44] have to keep going over to postman or
[21:46] going over to the user interface we can
[21:48] stay in the same places where our code
[21:50] lives just write our tests go make any
[21:52] changes we need to make to our entities
[21:54] to our attributes or things like that
[21:56] also when the test lets us know that
[21:58] something's going wrong
[22:00] if you've enjoyed this video and you'd
[22:01] like youtube to show you more of my
[22:03] content all you need to do is subscribe
[22:05] and click the notification icon each
[22:07] week i release a number of new
[22:08] recordings if you'd like to be informed
[22:10] about my upcoming videos as well as
[22:12] receive exclusive content discounts and
[22:15] early access to my new videos you can
[22:17] join my mailing list by following the
[22:19] link underneath this video
⚡ Saved you time reading this? Transcribe any YouTube video for free — no signup needed.