TubeSum ← Transcribe a video

API Platform Crash Course Part 13: Testing a REST API using PHPUnit

Transcribed Jun 17, 2026 Watch on YouTube ↗
Intermediate 8 min read For: PHP developers with basic Symfony and API Platform experience who want to add automated API testing.
5.4K
Views
78
Likes
8
Comments
0
Dislikes
1.6%
📊 Average

AI Summary

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

[0:00]
Goal of the video

The video focuses on setting up API testing with a separate test database, using packages for request simulation and JSON schema assertions.

[0:22]
Why a separate test database

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.

[1:46]
Creating the test database

Command: `symfony console --env=test doctrine:database:create`. This appends '_test' to the database name (e.g., `products_api_test`).

[2:30]
Migrating the test schema

Command: `symfony console --env=test doctrine:migrations:migrate` creates the tables (manufacturer, product) in the test DB.

[3:01]
Required packages

Installed via Composer: `alice` (fixture generation), `symfony/test-pack` (PHPUnit + bridge), `symfony/http-client` (request simulation), `json-schema` (JSON schema assertions).

[3:56]
Setting up test fixtures

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_*'`.

[6:05]
Loading fixtures into test DB

Command: `symfony console --env=test doctrine:fixtures:load`. Must run in `test` environment to avoid populating the dev database.

[7:08]
Writing the first test class

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.

[8:25]
Testing GET collection endpoint

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

[9:56]
Asserting JSON subset (hydra:view)

Using `assertJsonContains()` with an array that includes `@context`, `@id`, and pagination keys (`hydra:view` → `@id`, `type`, `hydra:first`, `hydra:last`, etc.).

[10:32]
Failing test – pagination mismatch

Default pagination differs from expected; fixed by adding `pagination_items_per_page=5` attribute on the Product API resource.

[11:22]
Silencing deprecation notices

Add `<server name='SYMFONY_DEPRECATIONS_HELPER' value='disabled'/>` to `phpunit.xml.dist` under `<php>` to remove deprecation output.

[12:09]
Counting returned items

Use `assertCount(5, $response->toArray()['hydra:member'])` to verify the page returns exactly 5 products.

[13:01]
Testing pagination links

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

[14:40]
Testing POST (create product)

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.

[16:54]
Making issueDate writable

Noticed issueDate was not writable in the entity → added `@ApiProperty(writable=true)` or `product:write` group to allow POSTing it.

[17:55]
Testing PUT (update product)

Test `test_update_product`: PUT to `/api/products/1` with updated description, assert 200 and that the returned JSON reflects the change.

[18:45]
Testing validation – missing manufacturer

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.

[19:58]
Debugging with tests

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.

[21:36]
Final takeaway – TDD-like workflow

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.

Clickbait Check

95% Legit

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

Mentioned in this Video

Tutorial Checklist

1 1:46 Create test database: run `symfony console --env=test doctrine:database:create`.
2 2:30 Migrate schema to test database: `symfony console --env=test doctrine:migrations:migrate`.
3 3:01 Install required packages: `composer require --dev alice symfony/test-pack symfony/http-client json-schema`.
4 3:56 Create YAML fixture files for Manufacturer and Product (in `fixtures/`). Define entity class and field values.
5 6:05 Load fixtures into test database: `symfony console --env=test doctrine:fixtures:load`.
6 7:08 Create test class in `tests/` extending `ApiTestCase`. Use `RefreshDatabaseTrait` for database isolation.
7 8:25 Write test for GET collection: create client, send GET to `/api/products`, assert 200, check Content-Type header, and validate JSON subset using `assertJsonContains()`.
8 11:22 Silence deprecation notices by adding `<server name='SYMFONY_DEPRECATIONS_HELPER' value='disabled'/>` in `phpunit.xml.dist`.
9 12:09 Count returned items: `$response->toArray()['hydra:member']` and `assertCount(5, ...)`.
10 13:01 Write pagination test: GET `/api/products?page=2`, assert `hydra:view` contains correct first/last/next/previous links.
11 14:40 Write POST (create) test: POST JSON body to `/api/products`, assert 201 status, check response body fields.
12 17:55 Write PUT (update) test: PUT updated description to `/api/products/1`, assert 200 and updated JSON.
13 18:45 Write validation test: POST invalid data (e.g., null manufacturer), assert 422. Add `@Assert otNull` and writable group as needed.

Study Flashcards (10)

Why is a separate test database recommended?

easy Click to reveal answer

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?

easy Click to reveal answer

`symfony console --env=test doctrine:database:create`

1:46

Which package generates fake fixture data in Symfony tests?

medium Click to reveal answer

Alice (DoctrineFixturesBundle's Alice).

3:01

What is the purpose of the `RefreshDatabaseTrait`?

medium Click to reveal answer

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?

medium Click to reveal answer

Using `$client->assertJsonContains([...])` with an array of expected keys/values.

9:43

What command migrates the schema to the test database?

easy Click to reveal answer

`symfony console --env=test doctrine:migrations:migrate`

2:30

How can you silence deprecation notices in PHPUnit output?

medium Click to reveal answer

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?

hard Click to reveal answer

Use `assertCount(5, $response->toArray()['hydra:member'])`.

12:09

What status code should a successful POST to create a resource return?

easy Click to reveal answer

201 (Created).

14:40

How do you pass the manufacturer relation when creating a product in a test?

hard Click to reveal answer

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

💡 Key Takeaways

⚖️

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:22
🔧

RefreshDatabaseTrait

Introduces a powerful trait that fully automates fixture reloading and transaction rollback, dramatically simplifying test setup.

7:56
🔧

JSON subset assertion

Demonstrates a flexible way to verify API responses without requiring an exact match, focusing only on the relevant parts.

9:56
💡

Test 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:45
⚖️

TDD-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

✂️ Creator Tools: Viral Hooks

AI-generated clip ideas for Shorts based on the transcript

Why you need a separate test database

53s

Clear, practical tip for developers on avoiding test data pollution.

▶ Play Clip

How to create test data with relationships

47s

Demonstrates a common challenge in testing relational data with fixtures.

▶ Play Clip

Watch a test fail and get fixed in seconds

50s

Real debugging action showing how to fix pagination test failure.

▶ Play Clip

Why your validation test might pass when it shouldn't

54s

Shows a common mistake with nullable fields and how to fix it.

▶ Play Clip

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