ApiaryのDreddユーティリティで文書化されたAPIをテストする

みんな大好き 何もしない よく文書化されたAPIを使用します。 BlueprintまたはSwagger API標準を使用すると、機械可読および人間可読のドキュメントを取得できるため、そのドキュメントに基づいたAPI検証ツールを入手できます。







Apiaryは、ドキュメントから生成されたフォームの必要なパラメーターを置き換えて、APIを手動でチェックするための対話型ツールを提供します。 ただし、APIが自動的にチェックされると、さらに多くを得ることができます。 これにより、インターフェイスごとに個別のテストを記述する必要がなくなりますが、ドキュメント自体の構造と品質に特定の制限が課せられます。







画像







このチュートリアルでは、GitHub APIの例を使用して、 Dreddユーティリティについて説明します。







画像







ブートストラップ



すでにVagrantGitがローカルにインストールされていると思います。 私はMacOSで作業していますが、以下のすべてのコマンドがMacOSで実行されました。







必要なアカウントと権限を準備します。







Apiaryサービスに新しいプロジェクトを登録して作成します。







画像







作成されたプロジェクトで、「テスト」>「チュートリアル」タブを開きます。 ここで、 apiaryApiKey



apiaryApiKey



値を記述する必要がありますが、これはapiaryApiKey









画像







GitHub設定で、次の権限(スコープ)でAPIにアクセスするためのトークンを作成しますgist、user:email 利用可能な権限については GitHub API ドキュメントをご覧ください。







トークンをコピーすることを忘れないでください 。 一度だけ表示されます。







画像







作業ディレクトリを作成します。







mkdir ~/dredd_test && cd ~/dredd_test && git init









仮想環境



OSが乱雑にならないよう、また実行したすべての手順を文書化するために、仮想環境を準備します。







mkdir vagrant && touch vagrant/Vagrantfile && git add vagrant/









ルートディレクトリで、 .gitignore



ファイルを作成し、そこに例外を追加します。







echo 'vagrant/.vagrant' >> .gitignore && git add .gitignore









vagrant/Vagrantfile



編集し、次の構成を追加します。







vagrant / vagrantfile
 Vagrant.require_version ">= 1.5" Vagrant.configure("2") do |config| config.vm.hostname = "dredd.dev" config.vm.provider :virtualbox do |v| v.name = "dredd_test" v.customize [ "modifyvm", :id, "--name", "dredd_test", "--memory", 2048, "--natdnshostresolver1", "on", "--natdnsproxy1", "on", "--cpus", 2, ] end #     , # ..   Ubuntu/Debian      npm config.vm.box = "centos/7" # IP-   config.vm.network :private_network, ip: "192.168.99.105" config.ssh.forward_agent = true #        , #            if ENV['DREDD_GITHUB_TEST_PATH'] config.vm.synced_folder "#{ENV['DREDD_GITHUB_TEST_PATH']}", "/var/dredd_test", :owner=> 'vagrant', :group=> 'vagrant' else #      -       config.vm.synced_folder "~/dredd_test", "/var/dredd_test", :owner=> 'vagrant', :group=> 'vagrant' end #          config.vm.provision :shell, path: "provision.sh" #      , #   GitHub API ,   Apiary  config.vm.provision "shell" do |s| s.binary = true # Replace Windows line endings with Unix line endings. s.inline = %Q(sudo echo \ "GITHUB_API_TOKEN=#{ENV['GITHUB_API_TOKEN']}\nAPIARY_API_KEY=#{ENV['APIARY_API_KEY']}\nAPIARY_API_NAME=#{ENV['APIARY_API_NAME']}" \ > /etc/environment ) end #  ,         VM config.vm.provision "shell" do |s| s.binary = true # Replace Windows line endings with Unix line endings. s.inline = %Q(cd /var/dredd_test && composer install && composer check) end end
      
      





次に、仮想マシンを準備するための一連の指示を含むファイルを準備する必要があります。







touch vagrant/provision.sh && git add vagrant/provision.sh









その中にテキストを入れてください:







vagrant / provision.sh
 #!/usr/bin/env bash yum -y clean all #    EPEL ( nodejs etc)  webtatic ( php) sudo rpm -Uvh https://dl.fedoraproject.org/pub/epel/epel-release-latest-7.noarch.rpm sudo rpm -Uvh https://mirror.webtatic.com/yum/el7/webtatic-release.rpm #    npm sudo curl --silent --location https://rpm.nodesource.com/setup_6.x | bash - yum -y update #   , #   PHP composer, #   API Dredd #   - Express JS   API sudo yum -y install curl git nodejs npm php70w-cli --skip-broken \ && curl -sS https://getcomposer.org/installer | sudo php -- --install-dir=/usr/bin --filename=composer \ && yum -y install gcc-c++ make \ && sudo npm cache clean \ && sudo npm install dredd -g \ && sudo npm install express -g \ && echo "Done"
      
      





ご覧のとおり、目的のDreddに加えて、PHP Composer依存関係マネージャーもインストールされます。 APIをテストするときにフックを記述するための例として、PHPが役立ちます。 これには他の言語 、たとえば同じNodeJを使用して、技術の「動物園」を作らないようにすることができます。 私のメイン言語はPHPなので、呼び出しコマンドを覚えないようにdreddをComposerに統合する方法を以下に示します。







これで、仮想環境の準備が整いました。







GitHub APIのブループリント



APIのドキュメントを準備する番です。 以下のインターフェースが実験動物として使用されました。









Dreddは、ブループリントAPIとSwaggerの2種類のドキュメントをサポートしています。 この標準はMarkdownマークアップに基づいており、お気に入りのgitサービス(Gitlab、Github、Bitbucketなど)でAPIのドキュメントを読むことができるため、最初のものを使用します。 さらに、Swaggerサポートはベータモードで発表されます。







プロジェクトのルートで、ファイルtouch github-api.md && git add github-api.md



を作成し、その中にドキュメントを配置します。

各行について詳しく説明しませんが、以下のリストの構造について説明します。







github-api.md
 FORMAT: 1A HOST: https://api.github.com/ # Github API test Just a simple test of GitHub API ## Users Collection [/users] ### OAuth Non-Web authentication flow: load user data [GET /users/technoweenie] + Request JSON (application/json; charset=utf-8) + Headers Authorization: token 12345 + Response 200 (application/json; charset=utf-8) + Headers Server: GitHub.com Date: Fri, 28 Jan 2017 02:30:40 GMT Content-Length: 1248 Status: 200 OK X-RateLimit-Limit: 5000 X-RateLimit-Remaining: 4992 X-RateLimit-Reset: 1485553884 Cache-Control: private, max-age=60, s-maxage=60 Vary: Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding ETag: "123456701aaf50ed0c83ad4123456789" Last-Modified: Fri, 02 Dec 2016 07:32:00 GMT X-OAuth-Scopes: gist, user:email X-GitHub-Media-Type: github.v3; format=json Access-Control-Expose-Headers: ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval Access-Control-Allow-Origin: * Content-Security-Policy: default-src 'none' Strict-Transport-Security: max-age=31536000; includeSubdomains; preload X-Content-Type-Options: nosniff X-Frame-Options: deny X-XSS-Protection: 1; mode=block X-Served-By: q1234567cned3f5c4u15a34csddc1234 X-GitHub-Request-Id: ABCD:EFGH:A5DA75D:2EF637A:12345678 Connection: close + Body { "login": "technoweenie", "id": 21, "avatar_url": "https://avatars.githubusercontent.com/u/21?v=3", "gravatar_id": "", "url": "https://api.github.com/users/technoweenie", "html_url": "https://github.com/technoweenie", "followers_url": "https://api.github.com/users/technoweenie/followers", "following_url": "https://api.github.com/users/technoweenie/following{/other_user}", "gists_url": "https://api.github.com/users/technoweenie/gists{/gist_id}", "starred_url": "https://api.github.com/users/technoweenie/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/technoweenie/subscriptions", "organizations_url": "https://api.github.com/users/technoweenie/orgs", "repos_url": "https://api.github.com/users/technoweenie/repos", "events_url": "https://api.github.com/users/technoweenie/events{/privacy}", "received_events_url": "https://api.github.com/users/technoweenie/received_events", "type": "User", "site_admin": true, "name": "risk danger olson", "company": "GitHub", "blog": "http://techno-weenie.net", "location": "Louisville, CO", "email": "technoweenie@gmail.com", "hireable": null, "bio": ":metal:", "public_repos": 164, "public_gists": 105, "followers": 2328, "following": 17, "created_at": "2008-01-14T04:33:35Z", "updated_at": "2017-01-24T10:45:13Z" } + Schema { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "login": { "type": "string" }, "id": { "type": "number" }, "avatar_url": { "type": ["string", "null"] }, "gravatar_id": { "type": ["string", "null"] }, "url": { "type": ["string", "null"] }, "html_url": { "type": ["string", "null"] }, "followers_url": { "type": ["string", "null"] }, "following_url": { "type": ["string", "null"] }, "gists_url": { "type": ["string", "null"] }, "starred_url": { "type": ["string", "null"] }, "subscriptions_url": { "type": ["string", "null"] }, "organizations_url": { "type": ["string", "null"] }, "repos_url": { "type": ["string", "null"] }, "events_url": { "type": ["string", "null"] }, "received_events_url": { "type": ["string", "null"] }, "type": { "type": ["string", "null"] }, "site_admin": { "type": "boolean" }, "name": { "type": ["string", "null"] }, "company": { "type": ["string", "null"] }, "blog": { "type": ["string", "null"] }, "location": { "type": ["string", "null"] }, "email": { "type": ["string", "null"] }, "hireable": { "type": ["boolean", "null"] }, "bio": { "type": ["string", "null"] }, "public_repos": { "type": ["number", "null"] }, "public_gists": { "type": ["number", "null"] }, "followers": { "type": ["number", "null"] }, "following": { "type": ["number", "null"] }, "created_at": { "type": ["string", "null"] }, "updated_at": { "type": ["string", "null"] } } } ## Gists Collection [/gists] ### Load all Gists [GET /gists] + Request JSON (application/json; charset=utf-8) + Response 200 (application/json; charset=utf-8) + Attributes (array[Gist], optional) ### Creating new Gist [POST] + Request JSON (application/json; charset=utf-8) + Headers Accept: application/json Authorization: token 12345 + Body { "description": "This is a simple test file for gist API check", "public": false, "files": { "file1.md": { "content": "# Hello, world\n- This is just a GitHub API testing result" } } } + Schema { "$schema": "http://json-schema.org/draft-04/schema#", "type": "object", "properties": { "files": { "type": "object" }, "description": { "type": ["string"] }, "public": { "type": ["boolean"] } }, "required": [ "files" ] } + Response 201 (application/json; charset=utf-8) + Attributes (Gist) ### Load a Gist [GET /gists/{id}] + Request JSON (application/json; charset=utf-8) + Parameters + id: a123456bcd (string) - The ID of the Gist. + Response 200 (application/json; charset=utf-8) + Attributes (Gist) ### Delete a Gist [DELETE /gists/{id}] + Parameters + id: a123456bcd (string) - The ID of the Gist. + Response 204 # Data Structures ## Gist This is a demo documentation example. Not all fields was included. + id: a123456bcd (string, required) + url: https://api.github.com/gists/{id} (string) + forks_url: https://api.github.com/gists/{id}/forks (string) + commits_url: https://api.github.com/gists/{id}/commits (string) + git_pull_url: https://gist.github.com/{id}.git (string) + public: false (boolean)
      
      





最初の2行は、標準のバージョンを理解し、デフォルトで使用するホストを理解するパーサーに必要です。これにより、対話形式でAPIを確認できます。







1、2、...レベルの見出しはさまざまに使用できます。 アナライザーでは、 [GET /users/technoweenie]



などの角括弧で指定すること[GET /users/technoweenie]



です。 このテキストは、たとえばApiaryでインタラクティブなフォームを作成するために使用されます。







画像







この設計の後、パーサーは、このインターフェースで予期される要求と応答の詳細を待ちます。 これを行うには、構成+ Request ( )



および+ Response http-status-code ( )









ネストされたレベルは次のとおりです。









したがって、上記の例は、要求と応答の本文にデータ構造を記述する2つの異なる方法を示しています。「洗練された」スキーマと、簡略化されたパラメーターと属性です。







文書を保存した後、ApiaryとGithubで読みやすく、手動で使用できることを確認できます。







作曲家プロジェクトの準備



このステップはオプションですが、ここでは、テストがプロジェクト自体の不可欠な部分である場合、より統合されたアプローチのために存在します。







git例外ファイルに新しい行を追加します: echo 'vendor/' >> .gitignore









composer.json



ファイルと、将来のフックのファイルを含むDreddフック用のフォルダーを作成します。







mkdir hooks && touch composer.json composer.lock hooks/github-api.php && echo '{}' > composer.lock && git add composer.* hooks/github-api.php









作曲家ファイルへ。 jsonはプロジェクトの説明を入力します:







composer.json
 { "name": "kivagant/github-api-test", "type": "project", "license": "MIT", "description": "Github API test example with dredd and Apiary", "require": { }, "require-dev": { "ddelnano/dredd-hooks-php": "^1.1" }, "scripts": { "check": [ "@test-mock", "@test" ], "test": "dredd --header=\"Authorization: token ${GITHUB_API_TOKEN}\" --config=./dredd-local.yml", "test-mock": "dredd --header=\"Authorization: token ${GITHUB_API_TOKEN}\" --config=./dredd.yml" } }
      
      





ここでは、次の点に注意する価値があります。









dreddを構成する



次に、実稼働用とAPIレイアウト用の2つの構成ファイルを作成します。







touch dredd.yml dredd-local.yml && git add dredd.yml dredd-local.yml









最初のdredd.yml



ファイルdredd.yml



は、次のパラメーターを記述します。その目的はドキュメントに記載されています







dredd.yml
 reporter: apiary #custom: # apiaryApiKey: 12345 # better to use console argument # apiaryApiName: abcdefg #header: ["Authorization: token 12345"] # better to use console argument dry-run: null hookfiles: hooks/*.php #   hooks language: vendor/bin/dredd-hooks-php #    composer- sandbox: false server-wait: 3 init: false names: false only: [] output: [] sorted: false user: null inline-errors: false details: false method: [] color: true level: info timestamp: false silent: false path: [] hooks-worker-timeout: 5000 hooks-worker-connect-timeout: 1500 hooks-worker-connect-retry: 500 hooks-worker-after-connect-wait: 100 hooks-worker-term-timeout: 5000 hooks-worker-term-retry: 500 hooks-worker-handler-host: localhost hooks-worker-handler-port: 61321 blueprint: github-api.md #   API Blueprint  endpoint: 'https://api.github.com' #  
      
      





同じテキストをdredd-local.yml



ファイルに配置する必要がありますが、最後に、 endpoint



パラメーターを置き換え、次のように追加のserver



パラメーターを追加しserver









dredd-local.yml
 #...   dredd.yml,  endpoint endpoint: 'http://localhost:3000' #   server: node app.js # ,       ""   API
      
      





この場合、Dreddはgithub-api.md



ファイルの内容を調べ、すべてのインターフェイスを1つずつ起動します。 しかし、これでは十分ではありません。 ドキュメントでは、次の操作を実行します。









最初の2つのケースでは、すべてが「箱から出して」そのままで問題ありませんが、特定のGistを取得して削除するには、作成したリソースの識別子を次のリクエストに渡す必要があります。 このために、Dreddフックが役立ちます。







ドレッドフックの作成



ファイルhooks/github-api.php



を開き、そこに次のコードを追加します。







フック/ github-api.php
 <?php //     use Dredd\Hooks; //       github-api.md //        , //         const DEFAULT_GIST_ID = "a123456bcd"; //      , //        $scope = [ 'lastGistId' => '' ]; //          Gist   Hooks::after("Gists Collection > Creating new Gist", function (&$transaction) use (&$scope) { $scope['lastGistId'] = ''; //      ,   if (!isset($transaction->real->body)) { //   ,      $transaction->fail = true; return; } $body = json_decode($transaction->real->body, true); //  JSON    if (!isset($body['id'])) { //      Gist,    $transaction->fail = true; return; } $scope['lastGistId'] = $body['id']; //        }); //   ,   API ,      //  Gist        Hooks::before("Gists Collection > Load a Gist", function (&$transaction) use (&$scope) { $transaction->expected->body = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->expected->body); $transaction->id = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->id); $transaction->request->uri = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->request->uri); $transaction->fullPath = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->fullPath); }); //   ,   API ,      //  Gist        Hooks::before("Gists Collection > Delete a Gist", function (&$transaction) use (&$scope) { $transaction->expected->body = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->expected->body); $transaction->id = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->id); $transaction->request->uri = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->request->uri); $transaction->fullPath = str_replace(DEFAULT_GIST_ID, $scope['lastGistId'], $transaction->fullPath); });
      
      





これでほぼすべての準備が整いましたが、完全を期すために、もう1ステップ追加します。







Express JSを使用したAPIプロトタイプの準備



git例外ファイルに新しい行を追加します: echo 'node_modules/' >> .gitignore









将来の「APIサーバー」用のファイルを作成します: touch app.js && git add app.js









このファイルに次のコンテンツを追加します。これは、githubの動作を単純にシミュレートします。 詳細については説明しません。







app.js
 var app = require('express')(); app.get('/', function(req, res) { res.json({message: 'Hello World!'}); }); app.get('/users/technoweenie', function(req, res) { res.set( { "Server": "GitHub-Mock.local", "Date": "Fri, 28 Jan 2017 02:31:55 GMT", "Content-Type": "application/json; charset=utf-8", "Content-Length": 1248, "Status": "200 OK", "X-RateLimit-Limit": 5000, "X-RateLimit-Remaining": 4992, "X-RateLimit-Reset": 1485553884, "Cache-Control": "private, max-age=60, s-maxage=60", "Vary": "Accept, Authorization, Cookie, X-GitHub-OTP, Accept-Encoding", "ETag": "\"123456701aaf50ed0c83ad4123456789\"", "Last-Modified": "Fri, 02 Dec 2016 07:32:00 GMT", "X-OAuth-Scopes": "gist, user:email", "X-Accepted-OAuth-Scopes": "", "X-GitHub-Media-Type": "github.v3; format=json", "Access-Control-Expose-Headers": "ETag, Link, X-GitHub-OTP, X-RateLimit-Limit, X-RateLimit-Remaining, X-RateLimit-Reset, X-OAuth-Scopes, X-Accepted-OAuth-Scopes, X-Poll-Interval", "Access-Control-Allow-Origin": "*", "Content-Security-Policy": "default-src 'none'", "Strict-Transport-Security": "max-age=31536000; includeSubdomains; preload", "X-Content-Type-Options": "nosniff", "X-Frame-Options": "deny", "X-XSS-Protection": "1; mode=block", "X-Served-By": "q1234567cned3f5c4u15a34csddc1234", "X-GitHub-Request-Id": "ABCD:EFGH:25DA75D:2EF637A:12345679" } ).json( { "login": "technoweenie", "id": 21, "avatar_url": "https://avatars.githubusercontent.com/u/21?v=3", "gravatar_id": "", "url": "https://api.github.com/users/technoweenie", "html_url": "https://github.com/technoweenie", "followers_url": "https://api.github.com/users/technoweenie/followers", "following_url": "https://api.github.com/users/technoweenie/following{/other_user}", "gists_url": "https://api.github.com/users/technoweenie/gists{/gist_id}", "starred_url": "https://api.github.com/users/technoweenie/starred{/owner}{/repo}", "subscriptions_url": "https://api.github.com/users/technoweenie/subscriptions", "organizations_url": "https://api.github.com/users/technoweenie/orgs", "repos_url": "https://api.github.com/users/technoweenie/repos", "events_url": "https://api.github.com/users/technoweenie/events{/privacy}", "received_events_url": "https://api.github.com/users/technoweenie/received_events", "type": "User", "site_admin": true, "name": "risk danger olson", "company": "GitHub", "blog": "http://techno-weenie.net", "location": "Louisville, CO", "email": "technoweenie@gmail.com", "hireable": null, "bio": ":metal:", "public_repos": 164, "public_gists": 105, "followers": 2328, "following": 17, "created_at": "2008-01-14T04:33:35Z", "updated_at": "2017-01-24T10:45:13Z" } ); }); app.get('/gists', function(req, res) { res.set( { "Server": "GitHub-Mock.local", "Date": "Fri, 28 Jan 2017 02:31:55 GMT", "Content-Type": "application/json; charset=utf-8" } ).json( [ { "url": "https://api.github.com/gists/12345678c62ca49gf313ahd156781234", "forks_url": "https://api.github.com/gists/12345678c62ca49gf313ahd156781234/forks", "commits_url": "https://api.github.com/gists/12345678c62ca49gf313ahd156781234/commits", "id": "12345678c62ca49gf313ahd156781234", "git_pull_url": "https://gist.github.com/12345678c62ca49gf313ahd156781234.git", "git_push_url": "https://gist.github.com/12345678c62ca49gf313ahd156781234.git", "html_url": "https://gist.github.com/12345678c62ca49gf313ahd156781234", "files": { "file.html": { "filename": "file.html", "type": "text/html", "language": "HTML", "raw_url": "https://gist.githubusercontent.com/anonymous/12345678c62ca49gf313ahd156781234/raw/1234ac2e64b06898787920a14f85511be/file.html", "size": 45934 } }, "public": true, "created_at": "2017-01-28T01:29:29Z", "updated_at": "2017-01-28T01:29:29Z", "description": "just a test", "comments": 0, "user": null, "comments_url": "https://api.github.com/gists/12345678c62ca49gf313ahd156781234/comments", "truncated": false } ] ); }); app.get('/gists/:id', function(req, res) { res.set( { "Server": "GitHub-Mock.local", "Date": "Fri, 28 Jan 2017 02:31:55 GMT", "Content-Type": "application/json; charset=utf-8" } ).json( { "url": "https://api.github.com/gists/" + req.params.id, "forks_url": "https://api.github.com/gists/" + req.params.id + "/forks", "commits_url": "https://api.github.com/gists/" + req.params.id + "/commits", "id": req.params.id, "git_pull_url": "https://gist.github.com/" + req.params.id + ".git", "git_push_url": "https://gist.github.com/" + req.params.id + ".git", "html_url": "https://gist.github.com/" + req.params.id, "files": { "file.html": { "filename": "file.html", "type": "text/html", "language": "HTML", "raw_url": "https://gist.githubusercontent.com/anonymous/" + req.params.id + "/raw/12345678910abc/file.html", "size": 45934 } }, "public": true, "created_at": "2017-01-28T01:29:29Z", "updated_at": "2017-01-28T01:29:29Z", "description": "just a test", "comments": 0, "user": null, "comments_url": "https://api.github.com/gists/" + req.params.id + "/comments", "truncated": false } ); }); app.post('/gists', function(req, res) { res.status(201).set( { "Server": "GitHub-Mock.local", "Date": "Fri, 28 Jan 2017 02:31:55 GMT", "Content-Type": "application/json; charset=utf-8" } ).json( { "url": "https://api.github.com/gists/d7b4325ac95ca49ef310aed14dfa8b15", "forks_url": "https://api.github.com/gists/d7b4325ac95ca49ef310aed14dfa8b15/forks", "commits_url": "https://api.github.com/gists/d7b4325ac95ca49ef310aed14dfa8b15/commits", "id": "d7b4325ac95ca49ef310aed14dfa8b15", "git_pull_url": "https://gist.github.com/d7b4325ac95ca49ef310aed14dfa8b15.git", "git_push_url": "https://gist.github.com/d7b4325ac95ca49ef310aed14dfa8b15.git", "html_url": "https://gist.github.com/d7b4325ac95ca49ef310aed14dfa8b15", "files": {}, "public": false } ); }); app.delete('/gists/:id', function(req, res) { res.status(204).set( { "Server": "GitHub-Mock.local", "Date": "Fri, 28 Jan 2017 02:31:55 GMT" } ).end(); }); app.listen(3000);
      
      





nodejs, :







touch package.json && git add package.json









:







package.js
 { "name": "dredd_test", "version": "1.0.0", "main": "index.js", "scripts": { "test": "echo \"Error: no test specified\" && exit 1" }, "author": "", "license": "MIT", "private": true, "description": "", "dependencies": { "dredd ": "^2.2.5", "express": "^4.14.0" } }
      
      





(, , "private": true, npm package.js npm ERR! code 1. , WARN, .)









 cd vagrant/ vagrant box update DREDD_GITHUB_TEST_PATH=~/dredd_test GITHUB_API_TOKEN=<your-token> APIARY_API_KEY=<your-key> APIARY_API_NAME=<your-project-name> vagrant up
      
      





«»:







 info: Configuration './dredd.yml' found, ignoring other arguments. info: Beginning Dredd testing... info: Found Hookfiles: 0=hooks/github-api.php info: Spawning `vendor/bin/dredd-hooks-php` hooks handler process. info: Hooks handler stdout: Starting server info: Successfully connected to hooks handler. Waiting 0.1s to start testing. pass: GET /users/technoweenie duration: NaNms pass: GET /gists duration: NaNms pass: POST /gists duration: NaNms pass: GET /gists/1f892b1c9fef3f3fc09fc66c11ad2027 duration: NaNms pass: DELETE /gists/1f892b1c9fef3f3fc09fc66c11ad2027 duration: NaNms info: Sending SIGTERM to hooks handler process. complete: 5 passing, 0 failing, 0 errors, 0 skipped, 5 total complete: Tests took 7286ms complete: See results in Apiary at: https://app.apiary.io/githubtest5/tests/run/bcb8184a-2365-4459-b898-20e9bea8a389 > dredd --header="Authorization: token ${GITHUB_API_TOKEN}" --config=./dredd-local.yml info: Configuration './dredd-local.yml' found, ignoring other arguments. info: Starting backend server process with command: node app.js info: Waiting 3 seconds for backend server process to start. info: Beginning Dredd testing... info: Found Hookfiles: 0=hooks/github-api.php info: Spawning `vendor/bin/dredd-hooks-php` hooks handler process. info: Hooks handler stdout: Starting server info: Successfully connected to hooks handler. Waiting 0.1s to start testing. pass: GET /users/technoweenie duration: NaNms pass: GET /gists duration: NaNms pass: POST /gists duration: NaNms pass: GET /gists/d7b4325ac95ca49ef310aed14dfa8b15 duration: NaNms pass: DELETE /gists/d7b4325ac95ca49ef310aed14dfa8b15 duration: NaNms info: Sending SIGTERM to hooks handler process. complete: 5 passing, 0 failing, 0 errors, 0 skipped, 5 total complete: Tests took 2779ms complete: See results in Apiary at: https://app.apiary.io/githubtest5/tests/run/625c2477-7384-48fa-8bb9-25e27af2a908 info: Sending SIGTERM to backend server process. info: Backend server process was killed.
      
      





, : , production. gist.github.com , .







GUI.







https://app.apiary.io/githubtest5/tests/run/625c2477-7384-48fa-8bb9-25e27af2a908





画像







?

- , provision.sh



- ( npm, ). vagrant ssh



, sudo , dredd express. — .

, provision- (provision up ):

DREDD_GITHUB_TEST_PATH=~/dredd_test GITHUB_API_TOKEN=<your-token> APIARY_API_KEY=<your-key> APIARY_API_NAME=<your-project-name> vagrant provision









vagrant ssh



, cd /var/dredd_test && composer check



.







.







git add . && git commit -m 'Dredd testing project initial state'









, .

.








All Articles