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);
}