Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit dataProvider from database

I have simple PostControllerTest class:

<?php

namespace AppBundle\Tests\Controller;

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;
use Symfony\Bundle\FrameworkBundle\Client;

class PostControllerTest extends WebTestCase
{
    /**
     * @var Client
     */
    private $client;

    public function setUp() {
        $this->client = static::createClient();

    }

    public function idProvider()
    {
        return [
            ["1"],
            ["2"],
            ["3"],
        ];
    }

    /**
     * @dataProvider idProvider
     */
    public function testGet($id)
    {
        $this->client->request('GET', '/post/'.$id);
        $this->assertTrue($this->client->getResponse()->isSuccessful());
    }
}

testGet method uses idProvider for making request like /post/{id} and asserting successful response, where {id} is real id of Post entity in database.

Everything is OK, but what if Post with id = 1 is going to be removed?

I need to fetch a few id's from database, for example last or\and random 3 ones and pass it into testGet as dataProvider (or not dataProvider?)

I use Symfony 2.8.3 with PHPUnit 5.2.11.

How to solve it? Any advice is appreciated. Thanks!

like image 397
mineroot Avatar asked Nov 30 '25 16:11

mineroot


2 Answers

You're supposed to ensure the 'right' state of your application before the tests are run. So instead of counting on a post to be there, you would use the setUp() method to create a new post with a given id and then, run the test.

It might be a good idea to run the tests against a blank, tests dedicated database. This would make your tests very predictable and as such you wouldn't have to worry about passing the id from the setUp method to your testCase.

Otherwise, you can either create a helper class with static method for storing 'things' which you can later extract. Another solution which might be sufficient in your case, would be to create a separate class property to store the post id in.

Hope this helps.

like image 99
Kuba Birecki Avatar answered Dec 02 '25 07:12

Kuba Birecki


This one is rather tricky, since as far as I'm aware, dataProviders cannot call contextualized methods but only static ones because they are called before the class's instantiation.

A work around would be to stop using dataProviders and do your loop in the assertions instead:

public function testGet($id)
{
    $howMany = 3;
    //This method should create posts using your Business Logic layer
    $posts = $this->createPosts($howMany);
    foreach($posts as $post){
        $this->client->request('GET', '/post/'.$post->getId());
        $this->assertTrue($this->client->getResponse()->isSuccessful());
    }
}

As an aside note, just to say that these tests tend to be rather slow, so I'd question myself if it's worth checking 3 times the same thing for the sake of it, instead of trying one that exists and another one that doesn't.

like image 37
hasumedic Avatar answered Dec 02 '25 05:12

hasumedic