Создание REST API с помощью AdonisJs и TDD, часть 2

вступление

Прошло много времени с тех пор часть 1прости за это.

В этой части мы продолжим наш Rest API фильмов с TDD. Мы пойдем немного быстрее, потому что теперь мы знаем, какой шаг нам нужно сделать, чтобы следовать подходу TDD.

Fail -> Pass -> Refactor

Быстрые исправления

В последней части мы используем для тестирования env базу данных postgres. В этом нет ничего страшного, можно пользоваться. Но я думаю, что в долгосрочной перспективе будет быстрее, если мы будем использовать SQLite.

Не беспокойтесь снова, Adonis упростил нам задачу. 😃

Первый забег

npm i -D sqlite3

Это установит диск, который нам нужен для SQLite, в качестве Dev Dependencies.

Теперь зайдите в свой файл .env.testing и поместите эти строки

DB_CONNECTION=sqlite
DB_HOST=127.0.0.1
DB_PORT=3306
DB_USER=root
DB_PASSWORD=
DB_DATABASE=movies_challenges_test

Не забудьте удалить другого, кто касается БД.

Теперь, если вы повторно запустите тест с adonis test вы должны увидеть, что все тесты пройдены

sqlite-test.png

Если вы сравните это с предыдущим, вы увидите, что мы стали немного быстрее. Это будет становиться все быстрее и больше тестов, которые мы добавим. SQLite — это БД в памяти.

pg-benchmark.png

Получить /api/вызовы

Здесь, как следует из названия, мы будем работать над запросом GET, который даст нам все вызовы в нашем API. На данный момент и для целей урока мы не будем беспокоиться о нумерации страниц и т. д.

adonis make:test GetChallenges

И выберите Функциональный тест

Перейти к новому файлу

test/functional/get-challenges.spec.js

Как и в предыдущем тестовом файле, нам нужно импортировать Фабрику и получить трейт.

'use strict'

const Factory = use('Factory')
const { test, trait } = use('Test/Suite')('Get Challenges')

trait('Test/ApiClient')
trait('Auth/Client')

test('make sure 2 + 2 is 4', async ({ assert, client }) => {
  assert.equal(2 + 2, 4)
})

Время написать первый тест. Во-первых, чего мы хотим добиться здесь? Для этих конечных точек мы хотим убедиться, что можем получить все вызовы, которые нам нужно сохранить в базе данных. Здесь это будет совсем просто.

'use strict'

const Factory = use('Factory')
const { test, trait } = use('Test/Suite')('Get Challenges')

trait('Test/ApiClient')
trait('Auth/Client')

test('can get all the challenges', async ({ assert, client }) => {
  const challenges = await Factory.model('App/Models/Challenge').createMany(3)

  const response = await client.get('/api/challenges').end()

  response.assertStatus(200)

  response.assertJSONSubset([
    { title: challenges[0].title },
    { title: challenges[1].title },
    { title: challenges[2].title }
  ])
})

Здесь мы сначала создаем 3 задачи, используя метод createMany на Factory. После того, как мы проверим, что статус ответа равен 200, а также ответ JSON имеет все 3 заголовка внутри возвращаемого массива.

ошибка-1.png

Если вы запустите тест, это то, что вы увидите.

Логично, что мы еще не создали маршрут. Перейдите в файл маршрута и добавьте

Route.get('/api/challenges', 'ChallengeController.all')

Теперь, если вы добавите эту строку в свой тестовый файл

console.log('error', response.error)

После ответа обещания решить вы увидите.

'RuntimeException: E_UNDEFINED_METHOD: Method all missing on App/Controllers/Http/ChallengeController\n> More details: 

Это нормально, мы используем несуществующий метод контроллера.

Зайдите в свой ChallengeController и добавьте этот метод

async all({ response, request }) {
  const challenges = await Challenge.all()

  return response.ok(challenges)
}

Теперь после запуска теста все должно быть зеленым 😃

Это вызовет метод all из вашей модели Challenge, и он вернет массив всех доступных задач. response.ok вернет объект JSON со статусом 200 OK 😃

Получить /api/вызовы/:id

Время поработать над получением одного вызова от его идентификатора.

Снова довольно простая работа, просто нужно выполнить этот шаг.

adonis make:test GetChallenge

Вы можете скопировать и вставить последний тест, который мы создали, чтобы получить все задачи, которые будут выглядеть почти одинаково.

'use strict'

const Factory = use('Factory')
const { test, trait } = use('Test/Suite')('Get Challenge')

trait('Test/ApiClient')
trait('Auth/Client')

test('can get a challenge by id', async ({ assert, client }) => {
  const challenges = await Factory.model('App/Models/Challenge').createMany(3)

  const challenge = challenges[0]

  const response = await client.get(`/api/challenges/${challenge.id}`).end()

  response.assertStatus(200)

  response.assertJSONSubset({ title: challenge.title, id: challenge.id })
})

Довольно простой, мы создаем 3 задачи, чтобы сделать его немного более реалистичным. После этого мы создаем переменную задачу, кто будет первым в массиве. Затем мы добавляем идентификатор к URL-адресу. В конце мы проверяем статус 200, а также JSON должен иметь как заголовок, так и идентификатор, соответствующие этой задаче.

ошибка-2.png

Выполните тот же шаг, который мы сделали ранее, поэтому перейдите к маршрутам и добавьте маршрут для этого.

Route.get('/api/challenges/:id', 'ChallengeController.show')

После этого ваш тест скажет, что у нас нет метода в вашем контроллере. Время добавить это

async show({ response }) {
  return response.ok({})
}

ошибка-3.png

Следующая ошибка важна, это та, которая проверяет, соответствует ли возвращаемый объект тому, что мы предполагали. Это вполне нормально, здесь произошел сбой, мы возвращаем пустой объект. Так что пора заставить это работать.

async show({ response, params }) {
  const challenge = await Challenge.find(params.id)

  return response.ok(challenge)
}

Для получения доступа к идентификатору params мы используем объект params, а затем вызываем find из модели Challenge.

Если вы запустите все тесты сейчас, все будет зеленым.

Но нам нужен еще один тест для этой конечной точки. Что произойдет, если идентификатор не существует?

Если вы попробуете, это не удастся. Довольно простой тест для написания

test('status 404 if id do not exist', async ({ assert, client }) => {
  const response = await client.get('/api/challenges/999').end()

  response.assertStatus(404)
})

Говорит ли ошибка, что 204 должно равняться 404? Ээээ странно, пора это исправить.

async show({ response, params }) {
  const challenge = await Challenge.findOrFail(params.id)

  return response.ok(challenge)
}

Да, нужно изменить только одно: findOrFail, как следует из названия, вернет 404, если объект не найден. 😃 Действительно красиво и легко 😃

Исходный код:

Конечное слово

Надеюсь, вам понравится это, не слишком, но мы начинаем понимать поток и видим, как TDD помогает нам быстрее продвигаться по реализации API.

В следующей части мы добавим пользователю способ получить все свои испытания. А также способ обновить и удалить вызов, если вы являетесь автором.

Удачного кодирования 😃

Похожие записи

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *