├── .eslintrc.yml ├── .gitignore ├── README.md ├── event.json ├── handler.js ├── handler.test.js ├── package.json └── serverless.yml /.eslintrc.yml: -------------------------------------------------------------------------------- 1 | 2 | extends: standard 3 | plugins: 4 | - standard 5 | - promise 6 | globals: 7 | describe: false 8 | it: false 9 | beforeEach: false 10 | afterEach: false 11 | beforeAll: false 12 | afterAll: false 13 | rules: 14 | no-console: 15 | - error 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # package directories 2 | node_modules 3 | jspm_packages 4 | 5 | # Serverless directories 6 | .serverless 7 | 8 | # Istanbul 9 | coverage 10 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Lambda UnitTest Sample(Node.js) 2 | -------------------------------------------------------------------------------- /event.json: -------------------------------------------------------------------------------- 1 | { 2 | "post_id": "aaaa" 3 | } 4 | -------------------------------------------------------------------------------- /handler.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const aws = require('aws-sdk') 3 | const dynamodb = new aws.DynamoDB.DocumentClient() 4 | 5 | module.exports.blog = (event, context, callback) => { 6 | return Promise.resolve().then(() => { 7 | if (!event.post_id) { 8 | return Promise.reject(responseBilder(400, {message: 'invalid param'})) 9 | } 10 | 11 | const params = { 12 | TableName: 'Blog', 13 | Key: { 14 | post_id: event.post_id 15 | } 16 | } 17 | return dynamodb.get(params).promise() 18 | }).then(data => { 19 | if (!Object.keys(data).length) { 20 | return Promise.reject(responseBilder(404, {message: 'can not find specified post'})) 21 | } else { 22 | return Promise.resolve(responseBilder(200, { 23 | post_title: data.Item.post_title, 24 | post_content: data.Item.post_content 25 | })) 26 | } 27 | }) 28 | .then(result => callback(null, result)) 29 | .catch(error => callback(error)) 30 | } 31 | 32 | const responseBilder = (statusCode, data) => { 33 | return JSON.stringify({ 34 | statusCode: statusCode, 35 | body: data 36 | }) 37 | } 38 | -------------------------------------------------------------------------------- /handler.test.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | const chai = require('chai') 3 | const sinon = require('sinon') 4 | const proxyquire = require('proxyquire') 5 | chai.use(require('chai-as-promised')) 6 | const expect = require('chai').expect 7 | 8 | describe('Blog Lambda', () => { 9 | let event 10 | let callback 11 | let context 12 | let lambda 13 | let proxyDynamoDB 14 | let dynamoDbGetStub 15 | 16 | beforeEach(() => { 17 | event = { 18 | post_id: 'your-post-id' 19 | } 20 | callback = (error, result) => { 21 | return new Promise((resolve, reject) => { 22 | error ? reject(error) : resolve(result) 23 | }) 24 | } 25 | context = {} 26 | proxyDynamoDB = class { 27 | get (params) { 28 | return { 29 | promise: () => {} 30 | } 31 | } 32 | } 33 | lambda = proxyquire('./handler', { 34 | 'aws-sdk': { 35 | DynamoDB: { 36 | DocumentClient: proxyDynamoDB 37 | } 38 | } 39 | }) 40 | }) 41 | 42 | it('Should return resolve when running successfully', () => { 43 | dynamoDbGetStub = sinon.stub(proxyDynamoDB.prototype, 'get') 44 | .returns({promise: () => { 45 | return Promise.resolve({ 46 | Item: { 47 | post_title: 'aa', 48 | post_content: 'bb' 49 | } 50 | }) 51 | }}) 52 | return expect(lambda.blog(event, context, callback)).to.be.fulfilled.then(result => { 53 | expect(dynamoDbGetStub.calledOnce).to.be.equal(true) 54 | expect(result).to.deep.equal(JSON.stringify({ 55 | statusCode: 200, 56 | body: {post_title: 'aa', post_content: 'bb'} 57 | })) 58 | }) 59 | }) 60 | 61 | it('Should return reject when post_id is not given', () => { 62 | event = {} 63 | dynamoDbGetStub = sinon.stub(proxyDynamoDB.prototype, 'get') 64 | .returns({promise: () => { 65 | return Promise.resolve({ 66 | Item: { 67 | post_title: 'aa', 68 | post_content: 'bb' 69 | } 70 | }) 71 | }}) 72 | return expect(lambda.blog(event, context, callback)).to.be.rejected.then(result => { 73 | expect(dynamoDbGetStub.calledOnce).to.be.equal(false) 74 | expect(result).to.deep.equal(JSON.stringify({ 75 | statusCode: 400, 76 | body: {message: 'invalid param'} 77 | })) 78 | }) 79 | }) 80 | 81 | it('Should return reject when you can not your item in DB', () => { 82 | dynamoDbGetStub = sinon.stub(proxyDynamoDB.prototype, 'get') 83 | .returns({promise: () => { 84 | return Promise.resolve({}) 85 | }}) 86 | return expect(lambda.blog(event, context, callback)).to.be.rejected.then(result => { 87 | expect(dynamoDbGetStub.calledOnce).to.be.equal(true) 88 | expect(result).to.deep.equal(JSON.stringify({ 89 | statusCode: 404, 90 | body: {message: 'can not find specified post'} 91 | })) 92 | }) 93 | }) 94 | 95 | it('Should return reject when error occurs in DB', () => { 96 | dynamoDbGetStub = sinon.stub(proxyDynamoDB.prototype, 'get') 97 | .returns({promise: () => { 98 | return Promise.reject('error') 99 | }}) 100 | return expect(lambda.blog(event, context, callback)).to.be.rejected.then(result => { 101 | expect(dynamoDbGetStub.calledOnce).to.be.equal(true) 102 | expect(result).to.be.equal('error') 103 | }) 104 | }) 105 | 106 | afterEach(() => { 107 | proxyDynamoDB.prototype.get.restore() 108 | }) 109 | }) 110 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "lambda-test-project", 3 | "version": "1.0.0", 4 | "description": "", 5 | "main": "handler.js", 6 | "scripts": { 7 | "test": "istanbul cover -x 'handler.test.js' node_modules/mocha/bin/_mocha 'handler.test.js' -- -R spec --recursive" 8 | }, 9 | "author": "", 10 | "license": "ISC", 11 | "dependencies": { 12 | "aws-sdk": "^2.78.0" 13 | }, 14 | "devDependencies": { 15 | "eslint": "^3.12.2", 16 | "eslint-config-standard": "^6.2.1", 17 | "eslint-plugin-import": "^1.16.0", 18 | "eslint-plugin-promise": "^3.4.0", 19 | "eslint-plugin-standard": "^2.0.1", 20 | "chai": "^4.0.2", 21 | "istanbul": "^0.4.5", 22 | "chai-as-promised": "^7.0.0", 23 | "mocha": "^3.4.2", 24 | "proxyquire": "^1.8.0", 25 | "sinon": "^2.3.5" 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /serverless.yml: -------------------------------------------------------------------------------- 1 | # Welcome to Serverless! 2 | # 3 | # This file is the main config file for your service. 4 | # It's very minimal at this point and uses default values. 5 | # You can always add more config options for more control. 6 | # We've included some commented out config examples here. 7 | # Just uncomment any of them to get that config option. 8 | # 9 | # For full config options, check the docs: 10 | # docs.serverless.com 11 | # 12 | # Happy Coding! 13 | 14 | service: aws-nodejs # NOTE: update this with your service name 15 | 16 | # You can pin your service to only deploy with a specific Serverless version 17 | # Check out our docs for more details 18 | # frameworkVersion: "=X.X.X" 19 | 20 | provider: 21 | name: aws 22 | runtime: nodejs6.10 23 | 24 | # you can overwrite defaults here 25 | # stage: dev 26 | # region: us-east-1 27 | 28 | # you can add statements to the Lambda function's IAM Role here 29 | iamRoleStatements: 30 | - Effect: "Allow" 31 | Action: 32 | - "dynamodb:GetItem" 33 | - "dynamodb:BatchGetItem" 34 | - "dynamodb:Query" 35 | - "dynamodb:PutItem" 36 | - "dynamodb:UpdateItem" 37 | - "dynamodb:DeleteItem" 38 | - "dynamodb:BatchWriteItem" 39 | - "dynamodb:Scan" 40 | Resource: 41 | - "arn:aws:dynamodb:us-east-1:*:table/Blog" 42 | # - Effect: "Allow" 43 | # Action: 44 | # - "s3:PutObject" 45 | # Resource: 46 | # Fn::Join: 47 | # - "" 48 | # - - "arn:aws:s3:::" 49 | # - "Ref" : "ServerlessDeploymentBucket" 50 | # - "/*" 51 | 52 | # you can define service wide environment variables here 53 | # environment: 54 | # variable1: value1 55 | 56 | # you can add packaging information here 57 | #package: 58 | # include: 59 | # - include-me.js 60 | # - include-me-dir/** 61 | # exclude: 62 | # - exclude-me.js 63 | # - exclude-me-dir/** 64 | 65 | functions: 66 | blog: 67 | handler: handler.blog 68 | 69 | # The following are a few example events you can configure 70 | # NOTE: Please make sure to change your handler code to work with those events 71 | # Check the event documentation for details 72 | # events: 73 | # - http: 74 | # path: users/create 75 | # method: get 76 | # - s3: ${env:BUCKET} 77 | # - schedule: rate(10 minutes) 78 | # - sns: greeter-topic 79 | # - stream: arn:aws:dynamodb:region:XXXXXX:table/foo/stream/1970-01-01T00:00:00.000 80 | # - alexaSkill 81 | # - iot: 82 | # sql: "SELECT * FROM 'some_topic'" 83 | # - cloudwatchEvent: 84 | # event: 85 | # source: 86 | # - "aws.ec2" 87 | # detail-type: 88 | # - "EC2 Instance State-change Notification" 89 | # detail: 90 | # state: 91 | # - pending 92 | # - cloudwatchLog: '/aws/lambda/hello' 93 | # - cognitoUserPool: 94 | # pool: MyUserPool 95 | # trigger: PreSignUp 96 | 97 | # Define function environment variables here 98 | # environment: 99 | # variable2: value2 100 | 101 | # you can add CloudFormation resource templates here 102 | #resources: 103 | # Resources: 104 | # NewResource: 105 | # Type: AWS::S3::Bucket 106 | # Properties: 107 | # BucketName: my-new-bucket 108 | # Outputs: 109 | # NewOutput: 110 | # Description: "Description for the output" 111 | # Value: "Some output value" 112 | --------------------------------------------------------------------------------