I'm currently building an API with Laravel 5 and I've written some unit (or integrated?) tests for it. I've been reading a little about unit test and how to not overdo it and I would like some input about what I have so far.

Most importantly, the most important part I don't like about my current code is the _database_seed() method, which I kind of need to make sure I have data to be pulled.

class StoreTest extends TestCase {

    use Helpers, Language;

    /**
     * Looks like a bad strategy
     */
    private function _database_seed() {
        $collection = factory(Store::class)->times(3)->create();
        $random = $collection->random();
        $data = ['name' => $random->name, 'slug' => $random->slug];
        return $data;
    }

    /**
     * @tests
     */
    public function it_should_get_all_stores() {
        $data = $this->_database_seed();

        $this->get('/stores', $this->header)
            ->assertResponseOk()
            ->seeJsonContains($data)
            ->seeInDatabase('shop', $data);
    }

    /**
     * @tests
     */
    public function it_should_get_one_store() {
        $data = $this->_database_seed();

        $this->get('/stores/' . $data['slug'], $this->header)
            ->assertResponseOk()
            ->seeJsonContains($data)
            ->seeInDatabase('shop', $data);
    }

    /**
     * @tests
     */
    public function it_should_404_when_slug_does_not_exist() {
        $fake = 'fake-slug';

        $this->get('/stores/' . $fake, $this->header)
            ->assertResponseStatus(404)
            ->seeJsonContains(['message' => $this->mockError('slug', ['slug' => $fake], 'stores')]);
    }

    /**
     * @tests
     */
    public function it_should_get_stores_recently_updated_through_news_route() {
        $future = Carbon::now()->addMonth();
        $tomorrow = Carbon::now()->addDay();

        $collection = factory(Store::class)->times(2)->create([
            'updated_at' => $future
        ]);

        $this->get('/news/stores/' . $tomorrow, $this->header)
            ->assertResponseStatus(200)
            ->seeJsonContains(['name' => $collection->random()->name])
            ->seeInDatabase('shop', ['name' => $collection->random()->name]);
    }

    /**
     * @tests
     */
    public function it_should_get_stores_recently_created_through_news_route() {
        $future = Carbon::now()->addMonth();
        $tomorrow = Carbon::now()->addDay();

        $collection = factory(Store::class)->times(2)->create([
            'created_at' => $future
        ]);

        $this->get('/news/stores/' . $tomorrow, $this->header)
            ->assertResponseStatus(200)
            ->seeJsonContains(['name' => $collection->random()->name])
            ->seeInDatabase('shop', ['name' => $collection->random()->name]);
    }
}

Update

Snippets of code being tested:

the $this->repository object comes from andersao/l5-repository package. and $this->response comes from dingo/api package. StoreTransformer follows the guidelines of thephpleague/fractal package.

it_should_get_all_stores

/**
 * Display a list of stores.
 *
 * @return \Illuminate\Http\Response
 * @Get("/stores")
 **/ 
public function index() {
    $stores = $this->repository->all();
    return $this->response->collection($stores, new StoreTransformer);
}

it_should_get_one_store / it_should_404_when_slug_does_not_exist

/**
 * Display a specific store by it's slug. Returns 404 in case the slug cannot be found in the database.
 *
 * @param  string $slug
 * @return \Illuminate\Http\Response
 * @Get("stores/{slug}")
 * @Versions({"v2"})
 */
public function show($slug) {
    $store = $this->repository->slug($slug);

    if (!$store)
        $this->response->errorNotFound($this->error('slug', ['slug' => $slug]));
    return $this->response->item($store, new StoreTransformer);
}

News related tests

/**
 * List all records updated or created after the given timestamp. Current allowed MODELS are **prizes** and **stores**.
 * @Get("/news/{model}/{timestamp}")
 * @Versions({"v2"})
 * @param $timestamp
 * @return \Dingo\Api\Http\Response
 */
public function news($timestamp) {
    $lastTime = Carbon::createFromFormat('Y-m-d H:i:s', $timestamp);
    return $this->response->collection($this->repository->news($lastTime), $this->transformer);
}

the news method is the following

public function news(Carbon $datetime) {
    return $this->pushCriteria(new News($datetime))->all();
}

and the criteria is this

/**
 * News constructor.
 * @param Carbon $lastTime
 */
public function __construct(Carbon $lastTime) {
    $this->lastTime = $lastTime;
}

public function apply($model, RepositoryInterface $repository) {
    return $model->where('created_at', '>=', $this->lastTime)
        ->orWhere('updated_at', '>=', $this->lastTime);
}
share|improve this question
    
Hard to do a code review on unit testing code without seeing the code that is under test. – Mike Brant Jul 6 '16 at 18:14
    
@MikeBrant sorry about that, it's just that the implementation were so small pieces of code that I ended up focusing more on the test itself and forgot that it could be important to see the code either way. – Marco Aurélio Deleu Jul 6 '16 at 19:18

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Browse other questions tagged or ask your own question.