Summer Sale! All accounts are 50% off this week.

Angelo Pio's avatar

Testing routes behaviur

Hello everyone I'm stepping in testing, and I love the concept of TDD. I've followed laravel 8 from scratch series, and now I'm trying to make some tests in order to exercise but I'm finding some difficulties. When I try to test the whole Feature of deleting/creating a post I find that when I invoke the $this->post method passing to it some data to create/delete a post it actually returns me a response that states it all went as expected but it does not commit changes to the db so I'm forced to hard coding something like

 'Post::factory()->create'

or

$post->delete() to make it work. 

So It seems to me that it isn't testing the feature properly if I have to hard code stuff instead of making the method do it, simulating a normal interaction

here is an example

public function a_post_can_only_be_created_by_an_admin()
    {

//        A user log as admin
        $admin = User::factory()->create(['username' => 'dragonlax']);
        $this->actingAs($admin);

//        goes to a onlyAdmin page to create Posts
        $response = $this->get('admin/posts/create');
        $response->assertViewIs('admin.posts.create');

//        fill the form with correct parameters and send a post request
        $post = Post::factory()
            ->create([
                'body' => 'Fake bosy',
                'user_id' => $admin->id,

            ]);
//        then the post is correctly being registered on the database
        $this->assertDatabaseHas('posts', $post->getAttributes());

0 likes
12 replies
MohamedTammam's avatar

First use RefreshDatabase in your test to refresh the database before every test.

In your test for create page you should assert that you see the right view file, bur for storing the post you need to send POST request. Don't fill the form. Filling the form and getting the post back is a process in end-to-end test no feature tests.

Your feature test for creating new post should look something like this.

public function test_storing_new_post()
{
	$admin = User::factory()->create(['username' => 'dragonlax']);
    $this->actingAs($admin);
	
	$this->post('admin/posts', [
			'body' => 'new post body',
	]);

	$this->assertDatabaseHas('posts', [
    	'body' => 'new post body',
		'user_id' => $admin->id,
	]);
}
Angelo Pio's avatar

@MohamedTammam thanks for the reply. I used DatabaseTransactions, is it the same? Then, I've already tried to write what you suggested me to but when I use post::factory()->make() (not create() so I can pass the data to the post method) then the assertDatabaseHas method reports me no post has been found , it tells me the table is empty

Angelo Pio's avatar

@MohamedTammam Yes I know it. So you're telling me the only way store the post is using the create method ? I thought the $this->post method would pass the data to the form like I would do by doing it manually

MohamedTammam's avatar

@Angelo Pio $this->post will send the data to your controller as you do with the form. If you use it just check after that the database to see whether the post is created or not. No need to use create method for that.

Angelo Pio's avatar

@MohamedTammam I'm sorry to bother you again on this but..it doesn't work! The test fails stating that the table is empty but if I use create() it does work. I'm sure the problem is not in the code of the post request made by the form because it works fine, and it is the ssame code made by Jeffrey Way in laravel from scratch series

$admin = User::factory()->create(['username' => 'dragonlax']);
        $this->actingAs($admin);

        $post = Post::factory()
            ->make([
                'user_id' => $admin->id,

            ])->getAttributes();

        $response = $this->post('/admin/posts/',$post);

        $this->assertDatabaseHas('posts', $post, 'sqlite_testing');
Angelo Pio's avatar

@MohamedTammam 'Failed asserting that a row in the table [posts] matches the attributes ' 'table is empty', it does not add the post to the db

Angelo Pio's avatar

@MohamedTammam

public function store()
    {
        $form_data = array_merge($this->validatePostRequest(), [
            'user_id' => auth()->user()->id,
            'thumbnail' => request()->file('thumbnail')->store('thumbnail'),
            'exerpt' => substr(request('body'), 0, 300) . ' ...'
        ]);

        Post::create($form_data);

        return redirect()->route('home')->with('success', 'Post added');

    }

protected function validatePostRequest(?Post $post = null): array
    {
        $post ??= new Post();

         return request()->validate([
            'body' => ['required'],
            'title' => ['required', 'min:10', 'max:255'],
            'slug' => ['required', 'max:255', Rule::unique('posts', 'slug')->ignore($post)],
            'thumbnail' => $post->exists ? ['max:51200','image', 'mimes:png,jpg,svg,jpeg'] : ['required', 'max:51200', 'image', 'mimes:png,jpg,svg,jpeg'],
            'category_id' => ['required', Rule::exists('categories', 'id')]
        ]);
    }

Please or to participate in this conversation.