{"action":"created","comment":{"url":"https://api.github.com/repos/serverless/serverless/pulls/comments/89508020","pull_request_review_id":10053026,"id":89508020,"diff_hunk":"@@ -12,17 +12,21 @@ layout: Doc\n \n # Testing\n \n-Serverless introduces a lot of simplifications when it comes to serving business logic. We only need to provide handler function that almost entirely implements business logic. The only thing that we need to apply to are handler function arguments that are passed by FaaS provider. E.g. AWS Lambda passes 3 arguments `event`, `context` and `callback` to Node.js functions. Of course list of arguments differs between languages and, what is more important, between FaaS providers.\n+While the Serverless Architecture introduces a lot of simplicity when it comes to serving business logic, some of its characteristics that present challenges for testing.  They are:\n \n-Another important factor is a cloud environment. Basically, it's impossible to emulate AWS locally. Of course projects like [dynamodb-local](http://docs.aws.amazon.com/amazondynamodb/latest/developerguide/DynamoDBLocal.html) or [kinesalite](https://github.com/mhart/kinesalite) may help but AWS (and other providers) provide much more services. We shouldn't rely on local implementations if we want to be 100% sure that our service won't fail after deploying to production environment.\n+* The Serverless Architecture is an integration of separate, distributed services, which must be tested both independently, and together.\n+* The Serverless Architecture is dependent on internet/cloud services, which are hard to emulate locally.\n+* The Serverless Architecture can feature event-driven, asynchronous workflows, which are hard to emulate entirely.\n \n-Because of those issues (and having [test pyramid](http://martinfowler.com/bliki/TestPyramid.html) in mind) we suggest following testing strategy:\n+To get through these challenges, and to keep the [test pyramid](http://martinfowler.com/bliki/TestPyramid.html) in mind, keep the following principles in mind:\n \n-- business logic should be independent from FaaS provider,\n-- unit testing should be used as a main tool for verifying business logic,\n-- integration tests should be used for verifying integration with other services.\n+* Write your business logic so that it is separate from your FaaS provider (e.g., AWS Lambda), to keep it provider-independent, reusable and more easily testable.\n+* When your business logic is written separately from the FaaS provider, you can write traditional Unit Tests to ensure it is working properly.\n+* Write Integration Tests to verify integrations with other services are working correctly.\n \n-Let's take simple Node.js function as an example. The responsibility of this function is to save user into DB and send welcome email:\n+## A Poor Example\n+\n+Here is an example in Node.js of how to follow the practices above.  This job this Function should perform is to save a user in a database and then send a welcome email:","path":"docs/providers/aws/guide/testing.md","position":25,"original_position":25,"commit_id":"03d9d8e73b108c54fe36863c478165c8363bff93","original_commit_id":"03d9d8e73b108c54fe36863c478165c8363bff93","user":{"login":"mthenw","id":455261,"avatar_url":"https://avatars.githubusercontent.com/u/455261?v=3","gravatar_id":"","url":"https://api.github.com/users/mthenw","html_url":"https://github.com/mthenw","followers_url":"https://api.github.com/users/mthenw/followers","following_url":"https://api.github.com/users/mthenw/following{/other_user}","gists_url":"https://api.github.com/users/mthenw/gists{/gist_id}","starred_url":"https://api.github.com/users/mthenw/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/mthenw/subscriptions","organizations_url":"https://api.github.com/users/mthenw/orgs","repos_url":"https://api.github.com/users/mthenw/repos","events_url":"https://api.github.com/users/mthenw/events{/privacy}","received_events_url":"https://api.github.com/users/mthenw/received_events","type":"User","site_admin":false},"body":"\"This job this Function\"","created_at":"2016-11-24T14:39:03Z","updated_at":"2016-11-24T14:39:03Z","html_url":"https://github.com/serverless/serverless/pull/2703#discussion_r89508020","pull_request_url":"https://api.github.com/repos/serverless/serverless/pulls/2703","_links":{"self":{"href":"https://api.github.com/repos/serverless/serverless/pulls/comments/89508020"},"html":{"href":"https://github.com/serverless/serverless/pull/2703#discussion_r89508020"},"pull_request":{"href":"https://api.github.com/repos/serverless/serverless/pulls/2703"}}},"pull_request":{"url":"https://api.github.com/repos/serverless/serverless/pulls/2703","id":93513590,"html_url":"https://github.com/serverless/serverless/pull/2703","diff_url":"https://github.com/serverless/serverless/pull/2703.diff","patch_url":"https://github.com/serverless/serverless/pull/2703.patch","issue_url":"https://api.github.com/repos/serverless/serverless/issues/2703","number":2703,"state":"open","locked":false,"title":"Documentation Improvements","user":{"login":"ac360","id":2752551,"avatar_url":"https://avatars.githubusercontent.com/u/2752551?v=3","gravatar_id":"","url":"https://api.github.com/users/ac360","html_url":"https://github.com/ac360","followers_url":"https://api.github.com/users/ac360/followers","following_url":"https://api.github.com/users/ac360/following{/other_user}","gists_url":"https://api.github.com/users/ac360/gists{/gist_id}","starred_url":"https://api.github.com/users/ac360/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/ac360/subscriptions","organizations_url":"https://api.github.com/users/ac360/orgs","repos_url":"https://api.github.com/users/ac360/repos","events_url":"https://api.github.com/users/ac360/events{/privacy}","received_events_url":"https://api.github.com/users/ac360/received_events","type":"User","site_admin":false},"body":"## Description:\r\n\r\n**Status:** WIP\r\n\r\nThis PR introduces some minor documentation improvements.  Here are its goals:\r\n\r\n- [x] Add in any missing pieces from the previous documentation.\r\n- [x] Create a `serverless.yml` reference document which lists all available properties of `serverless.yml` in one place.\r\n- [x] Clean up grammar, structural, typo mistakes.\r\n- [x] Reign in new Guide documents (i.e., version pinning -> services) and put them in sections that already exist for them.\r\n- [ ] Make sure each CLI command has a separate document.  Instead of burying commands in the documents of others.\r\n\r\n## Todos:\r\n\r\n- [ ] Write documentation\r\n- [ ] Change ready for review message below\r\n\r\n***Is this ready for review?:*** NO\r\n","created_at":"2016-11-14T06:21:36Z","updated_at":"2016-11-24T14:41:42Z","closed_at":null,"merged_at":null,"merge_commit_sha":"4648ec5109d22f41a3239ccfe7a9ca2d5a7a1474","assignee":null,"assignees":[],"milestone":null,"commits_url":"https://api.github.com/repos/serverless/serverless/pulls/2703/commits","review_comments_url":"https://api.github.com/repos/serverless/serverless/pulls/2703/comments","review_comment_url":"https://api.github.com/repos/serverless/serverless/pulls/comments{/number}","comments_url":"https://api.github.com/repos/serverless/serverless/issues/2703/comments","statuses_url":"https://api.github.com/repos/serverless/serverless/statuses/03d9d8e73b108c54fe36863c478165c8363bff93","head":{"label":"serverless:improve-docs-v3","ref":"improve-docs-v3","sha":"03d9d8e73b108c54fe36863c478165c8363bff93","user":{"login":"serverless","id":13742415,"avatar_url":"https://avatars.githubusercontent.com/u/13742415?v=3","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"repo":{"id":34302698,"name":"serverless","full_name":"serverless/serverless","owner":{"login":"serverless","id":13742415,"avatar_url":"https://avatars.githubusercontent.com/u/13742415?v=3","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/serverless/serverless","description":"Serverless Framework – Build web, mobile and IoT applications with serverless architectures using AWS Lambda, Azure Functions, Google CloudFunctions & more! – ","fork":false,"url":"https://api.github.com/repos/serverless/serverless","forks_url":"https://api.github.com/repos/serverless/serverless/forks","keys_url":"https://api.github.com/repos/serverless/serverless/keys{/key_id}","collaborators_url":"https://api.github.com/repos/serverless/serverless/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/serverless/serverless/teams","hooks_url":"https://api.github.com/repos/serverless/serverless/hooks","issue_events_url":"https://api.github.com/repos/serverless/serverless/issues/events{/number}","events_url":"https://api.github.com/repos/serverless/serverless/events","assignees_url":"https://api.github.com/repos/serverless/serverless/assignees{/user}","branches_url":"https://api.github.com/repos/serverless/serverless/branches{/branch}","tags_url":"https://api.github.com/repos/serverless/serverless/tags","blobs_url":"https://api.github.com/repos/serverless/serverless/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/serverless/serverless/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/serverless/serverless/git/refs{/sha}","trees_url":"https://api.github.com/repos/serverless/serverless/git/trees{/sha}","statuses_url":"https://api.github.com/repos/serverless/serverless/statuses/{sha}","languages_url":"https://api.github.com/repos/serverless/serverless/languages","stargazers_url":"https://api.github.com/repos/serverless/serverless/stargazers","contributors_url":"https://api.github.com/repos/serverless/serverless/contributors","subscribers_url":"https://api.github.com/repos/serverless/serverless/subscribers","subscription_url":"https://api.github.com/repos/serverless/serverless/subscription","commits_url":"https://api.github.com/repos/serverless/serverless/commits{/sha}","git_commits_url":"https://api.github.com/repos/serverless/serverless/git/commits{/sha}","comments_url":"https://api.github.com/repos/serverless/serverless/comments{/number}","issue_comment_url":"https://api.github.com/repos/serverless/serverless/issues/comments{/number}","contents_url":"https://api.github.com/repos/serverless/serverless/contents/{+path}","compare_url":"https://api.github.com/repos/serverless/serverless/compare/{base}...{head}","merges_url":"https://api.github.com/repos/serverless/serverless/merges","archive_url":"https://api.github.com/repos/serverless/serverless/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/serverless/serverless/downloads","issues_url":"https://api.github.com/repos/serverless/serverless/issues{/number}","pulls_url":"https://api.github.com/repos/serverless/serverless/pulls{/number}","milestones_url":"https://api.github.com/repos/serverless/serverless/milestones{/number}","notifications_url":"https://api.github.com/repos/serverless/serverless/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/serverless/serverless/labels{/name}","releases_url":"https://api.github.com/repos/serverless/serverless/releases{/id}","deployments_url":"https://api.github.com/repos/serverless/serverless/deployments","created_at":"2015-04-21T03:48:40Z","updated_at":"2016-11-24T12:36:45Z","pushed_at":"2016-11-24T13:49:30Z","git_url":"git://github.com/serverless/serverless.git","ssh_url":"git@github.com:serverless/serverless.git","clone_url":"https://github.com/serverless/serverless.git","svn_url":"https://github.com/serverless/serverless","homepage":"http://www.serverless.com","size":91515,"stargazers_count":12879,"watchers_count":12879,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1044,"mirror_url":null,"open_issues_count":170,"forks":1044,"open_issues":170,"watchers":12879,"default_branch":"master"}},"base":{"label":"serverless:master","ref":"master","sha":"3733f49d3d9c419543051fbbb4dffa93ce916706","user":{"login":"serverless","id":13742415,"avatar_url":"https://avatars.githubusercontent.com/u/13742415?v=3","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"repo":{"id":34302698,"name":"serverless","full_name":"serverless/serverless","owner":{"login":"serverless","id":13742415,"avatar_url":"https://avatars.githubusercontent.com/u/13742415?v=3","gravatar_id":"","url":"https://api.github.com/users/serverless","html_url":"https://github.com/serverless","followers_url":"https://api.github.com/users/serverless/followers","following_url":"https://api.github.com/users/serverless/following{/other_user}","gists_url":"https://api.github.com/users/serverless/gists{/gist_id}","starred_url":"https://api.github.com/users/serverless/starred{/owner}{/repo}","subscriptions_url":"https://api.github.com/users/serverless/subscriptions","organizations_url":"https://api.github.com/users/serverless/orgs","repos_url":"https://api.github.com/users/serverless/repos","events_url":"https://api.github.com/users/serverless/events{/privacy}","received_events_url":"https://api.github.com/users/serverless/received_events","type":"Organization","site_admin":false},"private":false,"html_url":"https://github.com/serverless/serverless","description":"Serverless Framework – Build web, mobile and IoT applications with serverless architectures using AWS Lambda, Azure Functions, Google CloudFunctions & more! – ","fork":false,"url":"https://api.github.com/repos/serverless/serverless","forks_url":"https://api.github.com/repos/serverless/serverless/forks","keys_url":"https://api.github.com/repos/serverless/serverless/keys{/key_id}","collaborators_url":"https://api.github.com/repos/serverless/serverless/collaborators{/collaborator}","teams_url":"https://api.github.com/repos/serverless/serverless/teams","hooks_url":"https://api.github.com/repos/serverless/serverless/hooks","issue_events_url":"https://api.github.com/repos/serverless/serverless/issues/events{/number}","events_url":"https://api.github.com/repos/serverless/serverless/events","assignees_url":"https://api.github.com/repos/serverless/serverless/assignees{/user}","branches_url":"https://api.github.com/repos/serverless/serverless/branches{/branch}","tags_url":"https://api.github.com/repos/serverless/serverless/tags","blobs_url":"https://api.github.com/repos/serverless/serverless/git/blobs{/sha}","git_tags_url":"https://api.github.com/repos/serverless/serverless/git/tags{/sha}","git_refs_url":"https://api.github.com/repos/serverless/serverless/git/refs{/sha}","trees_url":"https://api.github.com/repos/serverless/serverless/git/trees{/sha}","statuses_url":"https://api.github.com/repos/serverless/serverless/statuses/{sha}","languages_url":"https://api.github.com/repos/serverless/serverless/languages","stargazers_url":"https://api.github.com/repos/serverless/serverless/stargazers","contributors_url":"https://api.github.com/repos/serverless/serverless/contributors","subscribers_url":"https://api.github.com/repos/serverless/serverless/subscribers","subscription_url":"https://api.github.com/repos/serverless/serverless/subscription","commits_url":"https://api.github.com/repos/serverless/serverless/commits{/sha}","git_commits_url":"https://api.github.com/repos/serverless/serverless/git/commits{/sha}","comments_url":"https://api.github.com/repos/serverless/serverless/comments{/number}","issue_comment_url":"https://api.github.com/repos/serverless/serverless/issues/comments{/number}","contents_url":"https://api.github.com/repos/serverless/serverless/contents/{+path}","compare_url":"https://api.github.com/repos/serverless/serverless/compare/{base}...{head}","merges_url":"https://api.github.com/repos/serverless/serverless/merges","archive_url":"https://api.github.com/repos/serverless/serverless/{archive_format}{/ref}","downloads_url":"https://api.github.com/repos/serverless/serverless/downloads","issues_url":"https://api.github.com/repos/serverless/serverless/issues{/number}","pulls_url":"https://api.github.com/repos/serverless/serverless/pulls{/number}","milestones_url":"https://api.github.com/repos/serverless/serverless/milestones{/number}","notifications_url":"https://api.github.com/repos/serverless/serverless/notifications{?since,all,participating}","labels_url":"https://api.github.com/repos/serverless/serverless/labels{/name}","releases_url":"https://api.github.com/repos/serverless/serverless/releases{/id}","deployments_url":"https://api.github.com/repos/serverless/serverless/deployments","created_at":"2015-04-21T03:48:40Z","updated_at":"2016-11-24T12:36:45Z","pushed_at":"2016-11-24T13:49:30Z","git_url":"git://github.com/serverless/serverless.git","ssh_url":"git@github.com:serverless/serverless.git","clone_url":"https://github.com/serverless/serverless.git","svn_url":"https://github.com/serverless/serverless","homepage":"http://www.serverless.com","size":91515,"stargazers_count":12879,"watchers_count":12879,"language":"JavaScript","has_issues":true,"has_downloads":true,"has_wiki":false,"has_pages":false,"forks_count":1044,"mirror_url":null,"open_issues_count":170,"forks":1044,"open_issues":170,"watchers":12879,"default_branch":"master"}},"_links":{"self":{"href":"https://api.github.com/repos/serverless/serverless/pulls/2703"},"html":{"href":"https://github.com/serverless/serverless/pull/2703"},"issue":{"href":"https://api.github.com/repos/serverless/serverless/issues/2703"},"comments":{"href":"https://api.github.com/repos/serverless/serverless/issues/2703/comments"},"review_comments":{"href":"https://api.github.com/repos/serverless/serverless/pulls/2703/comments"},"review_comment":{"href":"https://api.github.com/repos/serverless/serverless/pulls/comments{/number}"},"commits":{"href":"https://api.github.com/repos/serverless/serverless/pulls/2703/commits"},"statuses":{"href":"https://api.github.com/repos/serverless/serverless/statuses/03d9d8e73b108c54fe36863c478165c8363bff93"}}}}
{"actor":{"display_login":"mthenw"}}